summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/activate/activate.c79
-rw-r--r--src/analyze/analyze.c130
-rw-r--r--src/ask-password/ask-password.c91
-rw-r--r--src/basic/calendarspec.c35
-rw-r--r--src/basic/calendarspec.h1
-rw-r--r--src/basic/cgroup-util.c49
-rw-r--r--src/basic/cgroup-util.h31
-rw-r--r--src/basic/copy.c16
-rw-r--r--src/basic/cpu-set-util.c105
-rw-r--r--src/basic/cpu-set-util.h34
-rw-r--r--src/basic/env-util.c2
-rw-r--r--src/basic/fileio.c40
-rw-r--r--src/basic/fileio.h2
-rw-r--r--src/basic/hashmap.c35
-rw-r--r--src/basic/hashmap.h11
-rw-r--r--src/basic/log.c6
-rw-r--r--src/basic/log.h12
-rw-r--r--src/basic/macro.h39
-rw-r--r--src/basic/missing.h65
-rw-r--r--src/basic/prioq.c12
-rw-r--r--src/basic/process-util.c2
-rw-r--r--src/basic/ring.c209
-rw-r--r--src/basic/ring.h55
-rw-r--r--src/basic/selinux-util.c10
-rw-r--r--src/basic/selinux-util.h6
-rw-r--r--src/basic/siphash24.c245
-rw-r--r--src/basic/siphash24.h13
-rw-r--r--src/basic/smack-util.c3
-rw-r--r--src/basic/smack-util.h3
-rw-r--r--src/basic/socket-label.c7
-rw-r--r--src/basic/strv.c160
-rw-r--r--src/basic/strv.h9
-rw-r--r--src/basic/terminal-util.c176
-rw-r--r--src/basic/terminal-util.h50
-rw-r--r--src/basic/time-util.c161
-rw-r--r--src/basic/time-util.h10
-rw-r--r--src/basic/unit-name.c164
-rw-r--r--src/basic/unit-name.h227
-rw-r--r--src/basic/util.c453
-rw-r--r--src/basic/util.h75
-rw-r--r--src/basic/virt.c2
-rw-r--r--src/binfmt/binfmt.c19
-rw-r--r--src/boot/bootctl.c32
-rw-r--r--src/bootchart/svg.c20
-rw-r--r--src/bus-proxyd/bus-proxyd.c28
-rw-r--r--src/bus-proxyd/stdio-bridge.c20
-rw-r--r--src/cgls/cgls.c42
-rw-r--r--src/cgroups-agent/cgroups-agent.c2
-rw-r--r--src/cgtop/cgtop.c230
-rw-r--r--src/core/automount.c24
-rw-r--r--src/core/automount.h12
-rw-r--r--src/core/busname.c32
-rw-r--r--src/core/busname.h17
-rw-r--r--src/core/cgroup.c244
-rw-r--r--src/core/cgroup.h42
-rw-r--r--src/core/dbus-cgroup.c192
-rw-r--r--src/core/dbus-execute.c325
-rw-r--r--src/core/dbus-manager.c77
-rw-r--r--src/core/dbus-service.c34
-rw-r--r--src/core/dbus-socket.c22
-rw-r--r--src/core/dbus-unit.c26
-rw-r--r--src/core/device.c8
-rw-r--r--src/core/device.h13
-rw-r--r--src/core/execute.c394
-rw-r--r--src/core/execute.h29
-rw-r--r--src/core/failure-action.c2
-rw-r--r--src/core/job.c14
-rw-r--r--src/core/kill.c5
-rw-r--r--src/core/kill.h3
-rw-r--r--src/core/load-fragment-gperf.gperf.m412
-rw-r--r--src/core/load-fragment.c765
-rw-r--r--src/core/load-fragment.h4
-rw-r--r--src/core/machine-id-setup.c19
-rw-r--r--src/core/main.c519
-rw-r--r--src/core/manager.c151
-rw-r--r--src/core/manager.h25
-rw-r--r--src/core/mount-setup.c4
-rw-r--r--src/core/mount.c127
-rw-r--r--src/core/mount.h21
-rw-r--r--src/core/namespace.c44
-rw-r--r--src/core/path.c9
-rw-r--r--src/core/path.h12
-rw-r--r--src/core/scope.c14
-rw-r--r--src/core/scope.h14
-rw-r--r--src/core/selinux-setup.c6
-rw-r--r--src/core/service.c318
-rw-r--r--src/core/service.h32
-rw-r--r--src/core/shutdown.c23
-rw-r--r--src/core/slice.c10
-rw-r--r--src/core/slice.h11
-rw-r--r--src/core/smack-setup.c9
-rw-r--r--src/core/snapshot.c7
-rw-r--r--src/core/snapshot.h11
-rw-r--r--src/core/socket.c421
-rw-r--r--src/core/socket.h35
-rw-r--r--src/core/swap.c18
-rw-r--r--src/core/swap.h19
-rw-r--r--src/core/system.conf6
-rw-r--r--src/core/target.c7
-rw-r--r--src/core/target.h11
-rw-r--r--src/core/timer.c10
-rw-r--r--src/core/timer.h13
-rw-r--r--src/core/transaction.c6
-rw-r--r--src/core/unit.c163
-rw-r--r--src/core/unit.h28
-rw-r--r--src/cryptsetup/cryptsetup.c14
-rw-r--r--src/delta/delta.c27
-rw-r--r--src/detect-virt/detect-virt.c20
-rw-r--r--src/escape/escape.c9
-rw-r--r--src/firstboot/firstboot.c27
-rw-r--r--src/fsck/fsck.c10
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c8
-rw-r--r--src/hostname/hostnamectl.c20
-rw-r--r--src/hostname/hostnamed.c6
-rw-r--r--src/hwdb/hwdb.c20
-rw-r--r--src/import/export.c16
-rw-r--r--src/import/import-common.c3
-rw-r--r--src/import/import.c16
-rw-r--r--src/import/importd.c9
-rw-r--r--src/import/pull-common.c44
-rw-r--r--src/import/pull.c16
-rw-r--r--src/initctl/initctl.c2
-rw-r--r--src/journal-remote/journal-gatewayd.c33
-rw-r--r--src/journal-remote/journal-remote.c34
-rw-r--r--src/journal-remote/journal-upload.c20
-rw-r--r--src/journal/cat.c41
-rw-r--r--src/journal/catalog.c27
-rw-r--r--src/journal/coredumpctl.c32
-rw-r--r--src/journal/journal-file.c93
-rw-r--r--src/journal/journal-file.h15
-rw-r--r--src/journal/journal-send.c26
-rw-r--r--src/journal/journal-vacuum.c124
-rw-r--r--src/journal/journal-vacuum.h6
-rw-r--r--src/journal/journal-verify.c4
-rw-r--r--src/journal/journalctl.c151
-rw-r--r--src/journal/journald-gperf.gperf2
-rw-r--r--src/journal/journald-rate-limit.c14
-rw-r--r--src/journal/journald-server.c388
-rw-r--r--src/journal/journald-server.h9
-rw-r--r--src/journal/journald-stream.c7
-rw-r--r--src/journal/journald-stream.h4
-rw-r--r--src/journal/journald.c8
-rw-r--r--src/journal/journald.conf2
-rw-r--r--src/journal/test-journal-interleaving.c4
-rw-r--r--src/journal/test-journal-verify.c2
-rw-r--r--src/journal/test-journal.c4
-rw-r--r--src/libsystemd-network/arp-util.c153
-rw-r--r--src/libsystemd-network/arp-util.h (renamed from src/libsystemd-network/ipv4ll-internal.h)14
-rw-r--r--src/libsystemd-network/dhcp-server-internal.h2
-rw-r--r--src/libsystemd-network/ipv4ll-network.c91
-rw-r--r--src/libsystemd-network/ipv4ll-packet.c71
-rw-r--r--src/libsystemd-network/lldp-internal.c251
-rw-r--r--src/libsystemd-network/lldp-internal.h10
-rw-r--r--src/libsystemd-network/lldp-network.c27
-rw-r--r--src/libsystemd-network/lldp-network.h1
-rw-r--r--src/libsystemd-network/lldp-port.c9
-rw-r--r--src/libsystemd-network/lldp-port.h8
-rw-r--r--src/libsystemd-network/lldp-tlv.c342
-rw-r--r--src/libsystemd-network/lldp-tlv.h26
-rw-r--r--src/libsystemd-network/lldp.h13
-rw-r--r--src/libsystemd-network/network-internal.c16
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c29
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c8
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c16
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c56
-rw-r--r--src/libsystemd-network/sd-icmp6-nd.c30
-rw-r--r--src/libsystemd-network/sd-ipv4acd.c529
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c663
-rw-r--r--src/libsystemd-network/sd-lldp.c66
-rw-r--r--src/libsystemd-network/sd-pppoe.c10
-rw-r--r--src/libsystemd-network/test-acd.c117
-rw-r--r--src/libsystemd-network/test-dhcp-client.c2
-rw-r--r--src/libsystemd-network/test-dhcp-server.c17
-rw-r--r--src/libsystemd-network/test-dhcp6-client.c8
-rw-r--r--src/libsystemd-network/test-icmp6-rs.c6
-rw-r--r--src/libsystemd-network/test-ipv4ll-manual.c129
-rw-r--r--src/libsystemd-network/test-ipv4ll.c97
-rw-r--r--src/libsystemd-network/test-lldp.c246
-rw-r--r--src/libsystemd-network/test-pppoe.c17
-rw-r--r--src/libsystemd/libsystemd.sym8
-rw-r--r--src/libsystemd/sd-bus/bus-container.c11
-rw-r--r--src/libsystemd/sd-bus/bus-dump.c48
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h2
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c19
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c2
-rw-r--r--src/libsystemd/sd-bus/busctl.c60
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c192
-rw-r--r--src/libsystemd/sd-bus/test-bus-marshal.c31
-rw-r--r--src/libsystemd/sd-daemon/sd-daemon.c103
-rw-r--r--src/libsystemd/sd-device/device-enumerator.c6
-rw-r--r--src/libsystemd/sd-device/device-private.c8
-rw-r--r--src/libsystemd/sd-device/sd-device.c37
-rw-r--r--src/libsystemd/sd-event/sd-event.c42
-rw-r--r--src/libsystemd/sd-hwdb/hwdb-internal.h1
-rw-r--r--src/libsystemd/sd-id128/sd-id128.c2
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c9
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c11
-rw-r--r--src/libsystemd/sd-netlink/rtnl-message.c60
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c13
-rw-r--r--src/locale/localectl.c28
-rw-r--r--src/login/.gitignore1
-rw-r--r--src/login/70-power-switch.rules2
-rw-r--r--src/login/inhibit.c16
-rw-r--r--src/login/loginctl.c184
-rw-r--r--src/login/logind-action.c1
-rw-r--r--src/login/logind-dbus.c18
-rw-r--r--src/login/logind-user.c6
-rw-r--r--src/login/sysfs-show.c2
-rw-r--r--src/login/systemd-user.m4 (renamed from src/login/systemd-user)5
l---------src/machine-id-commit/Makefile1
-rw-r--r--src/machine-id-commit/machine-id-commit.c107
-rw-r--r--src/machine-id-setup/machine-id-setup-main.c36
-rw-r--r--src/machine/machine-dbus.c42
-rw-r--r--src/machine/machine-dbus.h2
-rw-r--r--src/machine/machine.c36
-rw-r--r--src/machine/machine.h1
-rw-r--r--src/machine/machinectl.c68
-rw-r--r--src/machine/machined-dbus.c16
-rw-r--r--src/modules-load/modules-load.c15
-rw-r--r--src/network/networkctl.c39
-rw-r--r--src/network/networkd-address-pool.c4
-rw-r--r--src/network/networkd-address.c285
-rw-r--r--src/network/networkd-address.h12
-rw-r--r--src/network/networkd-dhcp4.c44
-rw-r--r--src/network/networkd-dhcp6.c150
-rw-r--r--src/network/networkd-fdb.c2
-rw-r--r--src/network/networkd-ipv4ll.c38
-rw-r--r--src/network/networkd-link.c323
-rw-r--r--src/network/networkd-link.h8
-rw-r--r--src/network/networkd-manager.c182
-rw-r--r--src/network/networkd-netdev-bond.c6
-rw-r--r--src/network/networkd-netdev-bridge.c86
-rw-r--r--src/network/networkd-netdev-bridge.h4
-rw-r--r--src/network/networkd-netdev-gperf.gperf3
-rw-r--r--src/network/networkd-netdev-tunnel.c24
-rw-r--r--src/network/networkd-netdev-vxlan.c8
-rw-r--r--src/network/networkd-netdev.c3
-rw-r--r--src/network/networkd-netdev.h3
-rw-r--r--src/network/networkd-network-gperf.gperf170
-rw-r--r--src/network/networkd-network.c44
-rw-r--r--src/network/networkd-network.h2
-rw-r--r--src/network/networkd-route.c102
-rw-r--r--src/network/networkd-route.h5
-rw-r--r--src/network/networkd-util.c4
-rw-r--r--src/network/networkd-wait-online.c10
-rw-r--r--src/network/networkd.h2
-rw-r--r--src/network/test-network.c13
-rw-r--r--src/notify/notify.c21
-rw-r--r--src/nspawn/nspawn-expose-ports.c48
-rw-r--r--src/nspawn/nspawn-mount.c65
-rw-r--r--src/nspawn/nspawn-mount.h3
-rw-r--r--src/nspawn/nspawn-settings.c2
-rw-r--r--src/nspawn/nspawn.c59
-rw-r--r--src/nss-mymachines/nss-mymachines.c4
-rw-r--r--src/path/path.c12
-rw-r--r--src/resolve-host/resolve-host.c13
-rw-r--r--src/resolve/resolved-bus.c4
-rw-r--r--src/resolve/resolved-conf.c4
-rw-r--r--src/resolve/resolved-dns-answer.c21
-rw-r--r--src/resolve/resolved-dns-answer.h1
-rw-r--r--src/resolve/resolved-dns-cache.c119
-rw-r--r--src/resolve/resolved-dns-cache.h2
-rw-r--r--src/resolve/resolved-dns-query.c4
-rw-r--r--src/resolve/resolved-dns-query.h2
-rw-r--r--src/resolve/resolved-dns-question.c8
-rw-r--r--src/resolve/resolved-dns-question.h2
-rw-r--r--src/resolve/resolved-dns-rr.c24
-rw-r--r--src/resolve/resolved-dns-rr.h2
-rw-r--r--src/resolve/resolved-dns-server.c9
-rw-r--r--src/resolve/resolved-dns-transaction.c2
-rw-r--r--src/rfkill/rfkill.c432
-rw-r--r--src/run/run.c50
-rw-r--r--src/shared/architecture.h16
-rw-r--r--src/shared/ask-password-api.c364
-rw-r--r--src/shared/ask-password-api.h25
-rw-r--r--src/shared/base-filesystem.c12
-rw-r--r--src/shared/bus-util.c161
-rw-r--r--src/shared/bus-util.h10
-rw-r--r--src/shared/conf-parser.c117
-rw-r--r--src/shared/conf-parser.h7
-rw-r--r--src/shared/dns-domain.c11
-rw-r--r--src/shared/dns-domain.h2
-rw-r--r--src/shared/dropin.c5
-rw-r--r--src/shared/fstab-util.c16
-rw-r--r--src/shared/fstab-util.h1
-rw-r--r--src/shared/install.c3
-rw-r--r--src/shared/logs-show.c12
-rw-r--r--src/shared/machine-image.c119
-rw-r--r--src/shared/pager.c27
-rw-r--r--src/shared/path-lookup.c6
-rw-r--r--src/shared/pty.c633
-rw-r--r--src/shared/pty.h72
-rw-r--r--src/shared/ptyfwd.c49
-rw-r--r--src/shared/ptyfwd.h12
-rw-r--r--src/shared/sleep-config.c2
-rw-r--r--src/shared/spawn-ask-password-agent.c12
-rw-r--r--src/shared/sysctl-util.c13
-rw-r--r--src/sleep/sleep.c16
-rw-r--r--src/socket-proxy/socket-proxyd.c14
-rw-r--r--src/sysctl/sysctl.c25
-rw-r--r--src/systemctl/systemctl.c1951
-rw-r--r--src/systemd/sd-bus.h4
-rw-r--r--src/systemd/sd-daemon.h2
-rw-r--r--src/systemd/sd-dhcp-client.h10
-rw-r--r--src/systemd/sd-dhcp6-client.h10
-rw-r--r--src/systemd/sd-icmp6-nd.h14
-rw-r--r--src/systemd/sd-ipv4acd.h55
-rw-r--r--src/systemd/sd-ipv4ll.h9
-rw-r--r--src/systemd/sd-lldp.h43
-rw-r--r--src/systemd/sd-netlink.h5
-rw-r--r--src/systemd/sd-pppoe.h4
-rw-r--r--src/sysusers/sysusers.c61
-rw-r--r--src/sysv-generator/sysv-generator.c5
-rw-r--r--src/test/test-calendarspec.c47
-rw-r--r--src/test/test-daemon.c17
-rw-r--r--src/test/test-date.c41
-rw-r--r--src/test/test-env-replace.c6
-rw-r--r--src/test/test-execute.c16
-rw-r--r--src/test/test-fileio.c8
-rw-r--r--src/test/test-hashmap-plain.c6
-rw-r--r--src/test/test-prioq.c7
-rw-r--r--src/test/test-pty.c142
-rw-r--r--src/test/test-ring.c130
-rw-r--r--src/test/test-siphash24.c70
-rw-r--r--src/test/test-strip-tab-ansi.c4
-rw-r--r--src/test/test-strv.c86
-rw-r--r--src/test/test-util.c115
-rw-r--r--src/timedate/timedatectl.c22
-rw-r--r--src/timesync/timesyncd-conf.c2
-rw-r--r--src/timesync/timesyncd.c2
-rw-r--r--src/tmpfiles/tmpfiles.c49
-rw-r--r--src/tty-ask-password-agent/tty-ask-password-agent.c153
-rw-r--r--src/udev/.gitignore1
-rw-r--r--src/udev/ata_id/ata_id.c6
-rw-r--r--src/udev/net/link-config.c4
-rw-r--r--src/udev/net/link-config.h1
-rw-r--r--src/udev/udev-rules.c5
-rw-r--r--src/udev/udevadm-settle.c7
-rw-r--r--src/udev/udevd.c43
-rw-r--r--src/update-utmp/update-utmp.c21
340 files changed, 12208 insertions, 8523 deletions
diff --git a/src/activate/activate.c b/src/activate/activate.c
index 5318829442..4ece1367c1 100644
--- a/src/activate/activate.c
+++ b/src/activate/activate.c
@@ -19,26 +19,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
+#include <getopt.h>
#include <sys/epoll.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/wait.h>
-#include <getopt.h>
+#include <unistd.h>
-#include "systemd/sd-daemon.h"
+#include "sd-daemon.h"
-#include "socket-util.h"
-#include "build.h"
#include "log.h"
-#include "strv.h"
#include "macro.h"
#include "signal-util.h"
+#include "socket-util.h"
+#include "strv.h"
static char** arg_listen = NULL;
static bool arg_accept = false;
static char** arg_args = NULL;
static char** arg_setenv = NULL;
+static const char *arg_fdname = NULL;
static int add_epoll(int epoll_fd, int fd) {
struct epoll_event ev = {
@@ -137,8 +137,8 @@ static int launch(char* name, char **argv, char **env, int fds) {
length = strv_length(arg_setenv);
- /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */
- envp = new0(char *, length + 7);
+ /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, LISTEN_FDNAMES, NULL */
+ envp = new0(char *, length + 8);
if (!envp)
return log_oom();
@@ -146,7 +146,9 @@ static int launch(char* name, char **argv, char **env, int fds) {
if (strchr(*s, '='))
envp[n_env++] = *s;
else {
- _cleanup_free_ char *p = strappend(*s, "=");
+ _cleanup_free_ char *p;
+
+ p = strappend(*s, "=");
if (!p)
return log_oom();
envp[n_env] = strv_find_prefix(env, p);
@@ -165,15 +167,37 @@ static int launch(char* name, char **argv, char **env, int fds) {
(asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0))
return log_oom();
+ if (arg_fdname) {
+ char *e;
+
+ e = strappend("LISTEN_FDNAMES=", arg_fdname);
+ if (!e)
+ return log_oom();
+
+ for (i = 1; i < (unsigned) fds; i++) {
+ char *c;
+
+ c = strjoin(e, ":", arg_fdname, NULL);
+ if (!c) {
+ free(e);
+ return log_oom();
+ }
+
+ free(e);
+ e = c;
+ }
+
+ envp[n_env++] = e;
+ }
+
tmp = strv_join(argv, " ");
if (!tmp)
return log_oom();
log_info("Execing %s (%s)", name, tmp);
execvpe(name, argv, envp);
- log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp);
- return -errno;
+ return log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp);
}
static int launch1(const char* child, char** argv, char **env, int fd) {
@@ -290,6 +314,7 @@ static void help(void) {
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
+ ARG_FDNAME,
};
static const struct option options[] = {
@@ -298,11 +323,12 @@ static int parse_argv(int argc, char *argv[]) {
{ "listen", required_argument, NULL, 'l' },
{ "accept", no_argument, NULL, 'a' },
{ "setenv", required_argument, NULL, 'E' },
- { "environment", required_argument, NULL, 'E' }, /* alias */
+ { "environment", required_argument, NULL, 'E' }, /* legacy alias */
+ { "fdname", required_argument, NULL, ARG_FDNAME },
{}
};
- int c;
+ int c, r;
assert(argc >= 0);
assert(argv);
@@ -314,29 +340,34 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
- case 'l': {
- int r = strv_extend(&arg_listen, optarg);
+ case 'l':
+ r = strv_extend(&arg_listen, optarg);
if (r < 0)
- return r;
+ return log_oom();
break;
- }
case 'a':
arg_accept = true;
break;
- case 'E': {
- int r = strv_extend(&arg_setenv, optarg);
+ case 'E':
+ r = strv_extend(&arg_setenv, optarg);
if (r < 0)
- return r;
+ return log_oom();
break;
- }
+
+ case ARG_FDNAME:
+ if (!fdname_is_valid(optarg)) {
+ log_error("File descriptor name %s is not valid, refusing.", optarg);
+ return -EINVAL;
+ }
+
+ arg_fdname = optarg;
+ break;
case '?':
return -EINVAL;
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index d1ff156d12..4bf83eb329 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -20,25 +20,25 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <stdlib.h>
#include <getopt.h>
#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
+#include "analyze-verify.h"
#include "bus-error.h"
-#include "log.h"
-#include "build.h"
-#include "util.h"
-#include "strxcpyx.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "special.h"
+#include "bus-util.h"
#include "hashmap.h"
+#include "log.h"
#include "pager.h"
-#include "analyze-verify.h"
+#include "special.h"
+#include "strv.h"
+#include "strxcpyx.h"
#include "terminal-util.h"
+#include "unit-name.h"
+#include "util.h"
#define SCALE_X (0.1 / 1000.0) /* pixels per us */
#define SCALE_Y (20.0)
@@ -318,6 +318,10 @@ finish:
}
static void free_host_info(struct host_info *hi) {
+
+ if (!hi)
+ return;
+
free(hi->hostname);
free(hi->kernel_name);
free(hi->kernel_release);
@@ -328,6 +332,8 @@ static void free_host_info(struct host_info *hi) {
free(hi);
}
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info*, free_host_info);
+
static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -430,24 +436,25 @@ fail:
}
static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
- int r;
- struct host_info *host;
-
static const struct bus_properties_map hostname_map[] = {
- { "Hostname", "s", NULL, offsetof(struct host_info, hostname) },
- { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) },
- { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) },
- { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) },
+ { "Hostname", "s", NULL, offsetof(struct host_info, hostname) },
+ { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) },
+ { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) },
+ { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) },
{ "OperatingSystemPrettyName", "s", NULL, offsetof(struct host_info, os_pretty_name) },
{}
};
static const struct bus_properties_map manager_map[] = {
- { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
- { "Architecture", "s", NULL, offsetof(struct host_info, architecture) },
+ { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
+ { "Architecture", "s", NULL, offsetof(struct host_info, architecture) },
{}
};
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(free_host_infop) struct host_info *host;
+ int r;
+
host = new0(struct host_info, 1);
if (!host)
return log_oom();
@@ -458,7 +465,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
hostname_map,
host);
if (r < 0)
- goto fail;
+ log_debug_errno(r, "Failed to get host information from systemd-hostnamed: %s", bus_error_message(&error, r));
r = bus_map_all_properties(bus,
"org.freedesktop.systemd1",
@@ -466,13 +473,12 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
manager_map,
host);
if (r < 0)
- goto fail;
+ return log_error_errno(r, "Failed to get host information from systemd: %s", bus_error_message(&error, r));
*hi = host;
+ host = NULL;
+
return 0;
-fail:
- free_host_info(host);
- return r;
}
static int pretty_boot_time(sd_bus *bus, char **_buf) {
@@ -535,9 +541,9 @@ static void svg_graph_box(double height, double begin, double end) {
}
static int analyze_plot(sd_bus *bus) {
+ _cleanup_(free_host_infop) struct host_info *host = NULL;
struct unit_times *times;
struct boot_times *boot;
- struct host_info *host = NULL;
int n, m = 1, y=0;
double width;
_cleanup_free_ char *pretty_times = NULL;
@@ -557,7 +563,7 @@ static int analyze_plot(sd_bus *bus) {
n = acquire_time_data(bus, &times);
if (n <= 0)
- goto out;
+ return n;
qsort(times, n, sizeof(struct unit_times), compare_unit_start);
@@ -653,12 +659,12 @@ static int analyze_plot(sd_bus *bus) {
svg("<text x=\"20\" y=\"50\">%s</text>", pretty_times);
svg("<text x=\"20\" y=\"30\">%s %s (%s %s %s) %s %s</text>",
isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name,
- isempty(host->hostname) ? "" : host->hostname,
- isempty(host->kernel_name) ? "" : host->kernel_name,
- isempty(host->kernel_release) ? "" : host->kernel_release,
- isempty(host->kernel_version) ? "" : host->kernel_version,
- isempty(host->architecture) ? "" : host->architecture,
- isempty(host->virtualization) ? "" : host->virtualization);
+ strempty(host->hostname),
+ strempty(host->kernel_name),
+ strempty(host->kernel_release),
+ strempty(host->kernel_version),
+ strempty(host->architecture),
+ strempty(host->virtualization));
svg("<g transform=\"translate(%.3f,100)\">\n", 20.0 + (SCALE_X * boot->firmware_time));
svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time);
@@ -742,8 +748,6 @@ static int analyze_plot(sd_bus *bus) {
free_unit_times(times, (unsigned) n);
n = 0;
-out:
- free_host_info(host);
return n;
}
@@ -759,9 +763,9 @@ static int list_dependencies_print(const char *name, unsigned int level, unsigne
if (times) {
if (times->time)
- printf("%s%s @%s +%s%s", ANSI_HIGHLIGHT_RED_ON, name,
+ printf("%s%s @%s +%s%s", ANSI_HIGHLIGHT_RED, name,
format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC),
- format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ANSI_HIGHLIGHT_OFF);
+ format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ANSI_NORMAL);
else if (times->activated > boot->userspace_time)
printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
else
@@ -927,8 +931,8 @@ static int list_dependencies(sd_bus *bus, const char *name) {
if (times) {
if (times->time)
- printf("%s%s +%s%s\n", ANSI_HIGHLIGHT_RED_ON, id,
- format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ANSI_HIGHLIGHT_OFF);
+ printf("%s%s +%s%s\n", ANSI_HIGHLIGHT_RED, id,
+ format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ANSI_NORMAL);
else if (times->activated > boot->userspace_time)
printf("%s @%s\n", id, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
else
@@ -1217,10 +1221,8 @@ static int dump(sd_bus *bus, char **args) {
&error,
&reply,
"");
- if (r < 0) {
- log_error("Failed issue method call: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed issue method call: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &text);
if (r < 0)
@@ -1251,11 +1253,36 @@ static int set_log_level(sd_bus *bus, char **args) {
&error,
"s",
args[0]);
- if (r < 0) {
- log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
- return -EIO;
+ if (r < 0)
+ return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
+static int set_log_target(sd_bus *bus, char **args) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ assert(bus);
+ assert(args);
+
+ if (strv_length(args) != 1) {
+ log_error("This command expects one argument only.");
+ return -E2BIG;
}
+ r = sd_bus_set_property(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "LogTarget",
+ &error,
+ "s",
+ args[0]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r));
+
return 0;
}
@@ -1285,7 +1312,8 @@ static void help(void) {
" critical-chain Print a tree of the time critical chain of units\n"
" plot Output SVG graphic showing service initialization\n"
" dot Output dependency graph in dot(1) format\n"
- " set-log-level LEVEL Set logging threshold for systemd\n"
+ " set-log-level LEVEL Set logging threshold for manager\n"
+ " set-log-target TARGET Set logging target for manager\n"
" dump Output state serialization of service manager\n"
" verify FILE... Check unit files for correctness\n"
, program_invocation_short_name);
@@ -1339,9 +1367,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_USER:
arg_user = true;
@@ -1434,7 +1460,7 @@ int main(int argc, char *argv[]) {
else {
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
- r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus);
+ r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
@@ -1454,6 +1480,8 @@ int main(int argc, char *argv[]) {
r = dump(bus, argv+optind+1);
else if (streq(argv[optind], "set-log-level"))
r = set_log_level(bus, argv+optind+1);
+ else if (streq(argv[optind], "set-log-target"))
+ r = set_log_target(bus, argv+optind+1);
else
log_error("Unknown operation '%s'.", argv[optind]);
}
diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c
index abfd545c79..1a69d15908 100644
--- a/src/ask-password/ask-password.c
+++ b/src/ask-password/ask-password.c
@@ -20,36 +20,36 @@
***/
#include <errno.h>
-#include <unistd.h>
#include <getopt.h>
#include <stddef.h>
+#include <unistd.h>
+#include "ask-password-api.h"
+#include "def.h"
#include "log.h"
#include "macro.h"
#include "strv.h"
-#include "ask-password-api.h"
-#include "def.h"
static const char *arg_icon = NULL;
static const char *arg_id = NULL;
-static const char *arg_message = NULL;
-static bool arg_echo = false;
-static bool arg_use_tty = true;
+static const char *arg_keyname = NULL;
+static char *arg_message = NULL;
static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
-static bool arg_accept_cached = false;
static bool arg_multiple = false;
+static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE;
static void help(void) {
printf("%s [OPTIONS...] MESSAGE\n\n"
"Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
- " -h --help Show this help\n"
- " --icon=NAME Icon name\n"
- " --timeout=SEC Timeout in sec\n"
- " --echo Do not mask input (useful for usernames)\n"
- " --no-tty Ask question via agent even on TTY\n"
- " --accept-cached Accept cached passwords\n"
- " --multiple List multiple passwords if available\n"
- " --id=ID Query identifier (e.g. cryptsetup:/dev/sda5)\n"
+ " -h --help Show this help\n"
+ " --icon=NAME Icon name\n"
+ " --id=ID Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n"
+ " --keyname=NAME Kernel key name for caching passwords (e.g. \"cryptsetup\")\n"
+ " --timeout=SEC Timeout in seconds\n"
+ " --echo Do not mask input (useful for usernames)\n"
+ " --no-tty Ask question via agent even on TTY\n"
+ " --accept-cached Accept cached passwords\n"
+ " --multiple List multiple passwords if available\n"
, program_invocation_short_name);
}
@@ -62,7 +62,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NO_TTY,
ARG_ACCEPT_CACHED,
ARG_MULTIPLE,
- ARG_ID
+ ARG_ID,
+ ARG_KEYNAME,
};
static const struct option options[] = {
@@ -74,6 +75,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED },
{ "multiple", no_argument, NULL, ARG_MULTIPLE },
{ "id", required_argument, NULL, ARG_ID },
+ { "keyname", required_argument, NULL, ARG_KEYNAME },
{}
};
@@ -102,15 +104,15 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_ECHO:
- arg_echo = true;
+ arg_flags |= ASK_PASSWORD_ECHO;
break;
case ARG_NO_TTY:
- arg_use_tty = false;
+ arg_flags |= ASK_PASSWORD_NO_TTY;
break;
case ARG_ACCEPT_CACHED:
- arg_accept_cached = true;
+ arg_flags |= ASK_PASSWORD_ACCEPT_CACHED;
break;
case ARG_MULTIPLE:
@@ -121,6 +123,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_id = optarg;
break;
+ case ARG_KEYNAME:
+ arg_keyname = optarg;
+ break;
+
case '?':
return -EINVAL;
@@ -128,18 +134,20 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
- if (optind != argc - 1) {
- log_error("%s: required argument missing.", program_invocation_short_name);
- return -EINVAL;
+ if (argc > optind) {
+ arg_message = strv_join(argv + optind, " ");
+ if (!arg_message)
+ return log_oom();
}
- arg_message = argv[optind];
return 1;
}
int main(int argc, char *argv[]) {
- int r;
+ _cleanup_strv_free_ char **l = NULL;
usec_t timeout;
+ char **p;
+ int r;
log_parse_environment();
log_open();
@@ -153,36 +161,21 @@ int main(int argc, char *argv[]) {
else
timeout = 0;
- if (arg_use_tty && isatty(STDIN_FILENO)) {
- char *password = NULL;
-
- r = ask_password_tty(arg_message, timeout, arg_echo, NULL,
- &password);
- if (r >= 0) {
- puts(password);
- free(password);
- }
-
- } else {
- char **l;
-
- r = ask_password_agent(arg_message, arg_icon, arg_id, timeout,
- arg_echo, arg_accept_cached, &l);
- if (r >= 0) {
- char **p;
-
- STRV_FOREACH(p, l) {
- puts(*p);
+ r = ask_password_auto(arg_message, arg_icon, arg_id, arg_keyname, timeout, arg_flags, &l);
+ if (r < 0) {
+ log_error_errno(r, "Failed to query password: %m");
+ goto finish;
+ }
- if (!arg_multiple)
- break;
- }
+ STRV_FOREACH(p, l) {
+ puts(*p);
- strv_free(l);
- }
+ if (!arg_multiple)
+ break;
}
finish:
+ free(arg_message);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c
index 2dcc9c5575..a2296f4709 100644
--- a/src/basic/calendarspec.c
+++ b/src/basic/calendarspec.c
@@ -279,6 +279,9 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) {
fputc(':', f);
format_chain(f, 2, c->second);
+ if (c->utc)
+ fputs(" UTC", f);
+
r = fflush_and_check(f);
if (r < 0) {
free(buf);
@@ -657,6 +660,10 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
if (!c)
return -ENOMEM;
+ c->utc = endswith_no_case(p, "UTC");
+ if (c->utc)
+ p = strndupa(p, strlen(p) - strlen(" UTC"));
+
if (strcaseeq(p, "minutely")) {
r = const_chain(0, &c->second);
if (r < 0)
@@ -859,13 +866,13 @@ static int find_matching_component(const CalendarComponent *c, int *val) {
return r;
}
-static bool tm_out_of_bounds(const struct tm *tm) {
+static bool tm_out_of_bounds(const struct tm *tm, bool utc) {
struct tm t;
assert(tm);
t = *tm;
- if (mktime(&t) == (time_t) -1)
+ if (mktime_or_timegm(&t, utc) == (time_t) -1)
return true;
/* Did any normalization take place? If so, it was out of bounds before */
@@ -878,7 +885,7 @@ static bool tm_out_of_bounds(const struct tm *tm) {
t.tm_sec != tm->tm_sec;
}
-static bool matches_weekday(int weekdays_bits, const struct tm *tm) {
+static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) {
struct tm t;
int k;
@@ -886,7 +893,7 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm) {
return true;
t = *tm;
- if (mktime(&t) == (time_t) -1)
+ if (mktime_or_timegm(&t, utc) == (time_t) -1)
return false;
k = t.tm_wday == 0 ? 6 : t.tm_wday - 1;
@@ -904,7 +911,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
for (;;) {
/* Normalize the current date */
- mktime(&c);
+ mktime_or_timegm(&c, spec->utc);
c.tm_isdst = -1;
c.tm_year += 1900;
@@ -916,7 +923,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
c.tm_mday = 1;
c.tm_hour = c.tm_min = c.tm_sec = 0;
}
- if (r < 0 || tm_out_of_bounds(&c))
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc))
return r;
c.tm_mon += 1;
@@ -927,7 +934,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
c.tm_mday = 1;
c.tm_hour = c.tm_min = c.tm_sec = 0;
}
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_year ++;
c.tm_mon = 0;
c.tm_mday = 1;
@@ -938,14 +945,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
r = find_matching_component(spec->day, &c.tm_mday);
if (r > 0)
c.tm_hour = c.tm_min = c.tm_sec = 0;
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_mon ++;
c.tm_mday = 1;
c.tm_hour = c.tm_min = c.tm_sec = 0;
continue;
}
- if (!matches_weekday(spec->weekdays_bits, &c)) {
+ if (!matches_weekday(spec->weekdays_bits, &c, spec->utc)) {
c.tm_mday++;
c.tm_hour = c.tm_min = c.tm_sec = 0;
continue;
@@ -954,7 +961,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
r = find_matching_component(spec->hour, &c.tm_hour);
if (r > 0)
c.tm_min = c.tm_sec = 0;
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_mday ++;
c.tm_hour = c.tm_min = c.tm_sec = 0;
continue;
@@ -963,14 +970,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) {
r = find_matching_component(spec->minute, &c.tm_min);
if (r > 0)
c.tm_sec = 0;
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_hour ++;
c.tm_min = c.tm_sec = 0;
continue;
}
r = find_matching_component(spec->second, &c.tm_sec);
- if (r < 0 || tm_out_of_bounds(&c)) {
+ if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
c.tm_min ++;
c.tm_sec = 0;
continue;
@@ -991,13 +998,13 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
assert(next);
t = (time_t) (usec / USEC_PER_SEC) + 1;
- assert_se(localtime_r(&t, &tm));
+ assert_se(localtime_or_gmtime_r(&t, &tm, spec->utc));
r = find_next(spec, &tm);
if (r < 0)
return r;
- t = mktime(&tm);
+ t = mktime_or_timegm(&tm, spec->utc);
if (t == (time_t) -1)
return -EINVAL;
diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h
index 7baf318249..56dc02f391 100644
--- a/src/basic/calendarspec.h
+++ b/src/basic/calendarspec.h
@@ -36,6 +36,7 @@ typedef struct CalendarComponent {
typedef struct CalendarSpec {
int weekdays_bits;
+ bool utc;
CalendarComponent *year;
CalendarComponent *month;
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 94a25585b2..95fc2b9e5d 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2018,9 +2018,10 @@ int cg_mask_supported(CGroupMask *ret) {
mask |= CGROUP_CONTROLLER_TO_MASK(v);
}
- /* Currently, we only support the memory controller in
- * the unified hierarchy, mask everything else off. */
- mask &= CGROUP_MASK_MEMORY;
+ /* Currently, we only support the memory and pids
+ * controller in the unified hierarchy, mask
+ * everything else off. */
+ mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_PIDS;
} else {
CGroupController c;
@@ -2206,12 +2207,54 @@ bool cg_is_legacy_wanted(void) {
return !cg_is_unified_wanted();
}
+int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
+ uint64_t u;
+ int r;
+
+ if (isempty(s)) {
+ *ret = CGROUP_CPU_SHARES_INVALID;
+ return 0;
+ }
+
+ r = safe_atou64(s, &u);
+ if (r < 0)
+ return r;
+
+ if (u < CGROUP_CPU_SHARES_MIN || u > CGROUP_CPU_SHARES_MAX)
+ return -ERANGE;
+
+ *ret = u;
+ return 0;
+}
+
+int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
+ uint64_t u;
+ int r;
+
+ if (isempty(s)) {
+ *ret = CGROUP_BLKIO_WEIGHT_INVALID;
+ return 0;
+ }
+
+ r = safe_atou64(s, &u);
+ if (r < 0)
+ return r;
+
+ if (u < CGROUP_BLKIO_WEIGHT_MIN || u > CGROUP_BLKIO_WEIGHT_MAX)
+ return -ERANGE;
+
+ *ret = u;
+ return 0;
+}
+
static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
[CGROUP_CONTROLLER_CPU] = "cpu",
[CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
[CGROUP_CONTROLLER_BLKIO] = "blkio",
[CGROUP_CONTROLLER_MEMORY] = "memory",
[CGROUP_CONTROLLER_DEVICES] = "devices",
+ [CGROUP_CONTROLLER_PIDS] = "pids",
+ [CGROUP_CONTROLLER_NET_CLS] = "net_cls",
};
DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController);
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index 16d439fd9d..01359fa7cb 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -35,6 +35,8 @@ typedef enum CGroupController {
CGROUP_CONTROLLER_BLKIO,
CGROUP_CONTROLLER_MEMORY,
CGROUP_CONTROLLER_DEVICES,
+ CGROUP_CONTROLLER_PIDS,
+ CGROUP_CONTROLLER_NET_CLS,
_CGROUP_CONTROLLER_MAX,
_CGROUP_CONTROLLER_INVALID = -1,
} CGroupController;
@@ -48,9 +50,35 @@ typedef enum CGroupMask {
CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES),
+ CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS),
+ CGROUP_MASK_NET_CLS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_NET_CLS),
_CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
} CGroupMask;
+/* Special values for the cpu.shares attribute */
+#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1)
+#define CGROUP_CPU_SHARES_MIN UINT64_C(2)
+#define CGROUP_CPU_SHARES_MAX UINT64_C(262144)
+#define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024)
+
+static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) {
+ return
+ x == CGROUP_CPU_SHARES_INVALID ||
+ (x >= CGROUP_CPU_SHARES_MIN && x <= CGROUP_CPU_SHARES_MAX);
+}
+
+/* Special values for the blkio.weight attribute */
+#define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1)
+#define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10)
+#define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000)
+#define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500)
+
+static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) {
+ return
+ x == CGROUP_BLKIO_WEIGHT_INVALID ||
+ (x >= CGROUP_BLKIO_WEIGHT_MIN && x <= CGROUP_BLKIO_WEIGHT_MAX);
+}
+
/*
* General rules:
*
@@ -159,3 +187,6 @@ bool cg_is_legacy_wanted(void);
const char* cgroup_controller_to_string(CGroupController c) _const_;
CGroupController cgroup_controller_from_string(const char *s) _pure_;
+
+int cg_cpu_shares_parse(const char *s, uint64_t *ret);
+int cg_blkio_weight_parse(const char *s, uint64_t *ret);
diff --git a/src/basic/copy.c b/src/basic/copy.c
index b8cbe644d4..b20c178727 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -37,10 +37,14 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
assert(fdt >= 0);
/* Try btrfs reflinks first. */
- if (try_reflink && max_bytes == (uint64_t) -1) {
+ if (try_reflink &&
+ max_bytes == (uint64_t) -1 &&
+ lseek(fdf, 0, SEEK_CUR) == 0 &&
+ lseek(fdt, 0, SEEK_CUR) == 0) {
+
r = btrfs_reflink(fdf, fdt);
if (r >= 0)
- return r;
+ return 0; /* we copied the whole thing, hence hit EOF, return 0 */
}
for (;;) {
@@ -50,7 +54,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
if (max_bytes != (uint64_t) -1) {
if (max_bytes <= 0)
- return -EFBIG;
+ return 1; /* return > 0 if we hit the max_bytes limit */
if ((uint64_t) m > max_bytes)
m = (size_t) max_bytes;
@@ -75,7 +79,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
/* The try splice, unless we already tried */
if (try_splice) {
- n = splice(fdf, NULL, fdt, NULL, m, 0);
+ n = splice(fdf, NULL, fdt, NULL, m, 0);
if (n < 0) {
if (errno != EINVAL && errno != ENOSYS)
return -errno;
@@ -91,7 +95,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
/* As a fallback just copy bits by hand */
{
- char buf[m];
+ uint8_t buf[m];
n = read(fdf, buf, m);
if (n < 0)
@@ -111,7 +115,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
}
}
- return 0;
+ return 0; /* return 0 if we hit EOF earlier than the size limit */
}
static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c
new file mode 100644
index 0000000000..519583c167
--- /dev/null
+++ b/src/basic/cpu-set-util.c
@@ -0,0 +1,105 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2015 Lennart Poettering
+ Copyright 2015 Filipe Brandenburger
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "cpu-set-util.h"
+
+cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
+ cpu_set_t *c;
+ unsigned n = 1024;
+
+ /* Allocates the cpuset in the right size */
+
+ for (;;) {
+ c = CPU_ALLOC(n);
+ if (!c)
+ return NULL;
+
+ if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) {
+ CPU_ZERO_S(CPU_ALLOC_SIZE(n), c);
+
+ if (ncpus)
+ *ncpus = n;
+
+ return c;
+ }
+
+ CPU_FREE(c);
+
+ if (errno != EINVAL)
+ return NULL;
+
+ n *= 2;
+ }
+}
+
+int parse_cpu_set_and_warn(
+ const char *rvalue,
+ cpu_set_t **cpu_set,
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *lvalue) {
+
+ const char *whole_rvalue = rvalue;
+ _cleanup_cpu_free_ cpu_set_t *c = NULL;
+ unsigned ncpus = 0;
+
+ assert(lvalue);
+ assert(rvalue);
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ unsigned cpu;
+ int r;
+
+ r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
+ return r;
+ }
+ if (r == 0)
+ break;
+
+ if (!c) {
+ c = cpu_set_malloc(&ncpus);
+ if (!c)
+ return log_oom();
+ }
+
+ r = safe_atou(word, &cpu);
+ if (r < 0 || cpu >= ncpus) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", rvalue);
+ return -EINVAL;
+ }
+
+ CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
+ }
+
+ /* On success, sets *cpu_set and returns ncpus for the system. */
+ if (c) {
+ *cpu_set = c;
+ c = NULL;
+ }
+
+ return (int) ncpus;
+}
diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h
new file mode 100644
index 0000000000..19b457a684
--- /dev/null
+++ b/src/basic/cpu-set-util.h
@@ -0,0 +1,34 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010-2015 Lennart Poettering
+ Copyright 2015 Filipe Brandenburger
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sched.h>
+
+#include "macro.h"
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
+#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
+
+cpu_set_t* cpu_set_malloc(unsigned *ncpus);
+
+int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue);
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index 4804a67f91..ecb2192c4d 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -541,7 +541,7 @@ char **replace_env_argv(char **argv, char **env) {
STRV_FOREACH(i, argv) {
/* If $FOO appears as single word, replace it by the split up variable */
- if ((*i)[0] == '$' && (*i)[1] != '{') {
+ if ((*i)[0] == '$' && (*i)[1] != '{' && (*i)[1] != '$') {
char *e;
char **w, **m = NULL;
unsigned q;
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 4a9105f421..13a85e1158 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -775,15 +775,19 @@ int executable_is_script(const char *path, char **interpreter) {
/**
* Retrieve one field from a file like /proc/self/status. pattern
- * should start with '\n' and end with a ':'. Whitespace and zeros
- * after the ':' will be skipped. field must be freed afterwards.
+ * should not include whitespace or the delimiter (':'). pattern matches only
+ * the beginning of a line. Whitespace before ':' is skipped. Whitespace and
+ * zeros after the ':' will be skipped. field must be freed afterwards.
+ * terminator specifies the terminating characters of the field value (not
+ * included in the value).
*/
-int get_status_field(const char *filename, const char *pattern, char **field) {
+int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) {
_cleanup_free_ char *status = NULL;
char *t, *f;
size_t len;
int r;
+ assert(terminator);
assert(filename);
assert(pattern);
assert(field);
@@ -792,11 +796,31 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
if (r < 0)
return r;
- t = strstr(status, pattern);
- if (!t)
- return -ENOENT;
+ t = status;
+
+ do {
+ bool pattern_ok;
+
+ do {
+ t = strstr(t, pattern);
+ if (!t)
+ return -ENOENT;
+
+ /* Check that pattern occurs in beginning of line. */
+ pattern_ok = (t == status || t[-1] == '\n');
+
+ t += strlen(pattern);
+
+ } while (!pattern_ok);
+
+ t += strspn(t, " \t");
+ if (!*t)
+ return -ENOENT;
+
+ } while (*t != ':');
+
+ t++;
- t += strlen(pattern);
if (*t) {
t += strspn(t, " \t");
@@ -812,7 +836,7 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
t --;
}
- len = strcspn(t, WHITESPACE);
+ len = strcspn(t, terminator);
f = strndup(t, len);
if (!f)
diff --git a/src/basic/fileio.h b/src/basic/fileio.h
index 2e8148ff24..4998d4d042 100644
--- a/src/basic/fileio.h
+++ b/src/basic/fileio.h
@@ -48,4 +48,4 @@ int write_env_file(const char *fname, char **l);
int executable_is_script(const char *path, char **interpreter);
-int get_status_field(const char *filename, const char *pattern, char **field);
+int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field);
diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c
index 7d2a4160c6..20e7e51d9e 100644
--- a/src/basic/hashmap.c
+++ b/src/basic/hashmap.c
@@ -276,10 +276,8 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
},
};
-unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
- siphash24((uint8_t*) &u, p, strlen(p), hash_key);
- return (unsigned long) u;
+void string_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(p, strlen(p) + 1, state);
}
int string_compare_func(const void *a, const void *b) {
@@ -291,10 +289,8 @@ const struct hash_ops string_hash_ops = {
.compare = string_compare_func
};
-unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
- siphash24((uint8_t*) &u, &p, sizeof(p), hash_key);
- return (unsigned long) u;
+void trivial_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(&p, sizeof(p), state);
}
int trivial_compare_func(const void *a, const void *b) {
@@ -306,10 +302,8 @@ const struct hash_ops trivial_hash_ops = {
.compare = trivial_compare_func
};
-unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
- siphash24((uint8_t*) &u, p, sizeof(uint64_t), hash_key);
- return (unsigned long) u;
+void uint64_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(p, sizeof(uint64_t), state);
}
int uint64_compare_func(const void *_a, const void *_b) {
@@ -325,10 +319,8 @@ const struct hash_ops uint64_hash_ops = {
};
#if SIZEOF_DEV_T != 8
-unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
- siphash24((uint8_t*) &u, p, sizeof(dev_t), hash_key);
- return (unsigned long) u;
+void devt_hash_func(const void *p, struct siphash *state) {
+ siphash24_compress(p, sizeof(dev_t), state);
}
int devt_compare_func(const void *_a, const void *_b) {
@@ -379,7 +371,16 @@ static uint8_t *hash_key(HashmapBase *h) {
}
static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
- return (unsigned) (h->hash_ops->hash(p, hash_key(h)) % n_buckets(h));
+ struct siphash state;
+ uint64_t hash;
+
+ siphash24_init(&state, hash_key(h));
+
+ h->hash_ops->hash(p, &state);
+
+ siphash24_finalize((uint8_t*)&hash, &state);
+
+ return (unsigned) (hash % n_buckets(h));
}
#define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h
index 2af23024de..ed6a092d82 100644
--- a/src/basic/hashmap.h
+++ b/src/basic/hashmap.h
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include "macro.h"
+#include "siphash24.h"
#include "util.h"
/*
@@ -67,7 +68,7 @@ typedef struct {
#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
-typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]);
+typedef void (*hash_func_t)(const void *p, struct siphash *state);
typedef int (*compare_func_t)(const void *a, const void *b);
struct hash_ops {
@@ -75,28 +76,28 @@ struct hash_ops {
compare_func_t compare;
};
-unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
+void string_hash_func(const void *p, struct siphash *state);
int string_compare_func(const void *a, const void *b) _pure_;
extern const struct hash_ops string_hash_ops;
/* This will compare the passed pointers directly, and will not
* dereference them. This is hence not useful for strings or
* suchlike. */
-unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
+void trivial_hash_func(const void *p, struct siphash *state);
int trivial_compare_func(const void *a, const void *b) _const_;
extern const struct hash_ops trivial_hash_ops;
/* 32bit values we can always just embedd in the pointer itself, but
* in order to support 32bit archs we need store 64bit values
* indirectly, since they don't fit in a pointer. */
-unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
+void uint64_hash_func(const void *p, struct siphash *state);
int uint64_compare_func(const void *a, const void *b) _pure_;
extern const struct hash_ops uint64_hash_ops;
/* On some archs dev_t is 32bit, and on others 64bit. And sometimes
* it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */
#if SIZEOF_DEV_T != 8
-unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
+void devt_hash_func(const void *p, struct siphash *state) _pure_;
int devt_compare_func(const void *a, const void *b) _pure_;
extern const struct hash_ops devt_hash_ops = {
.hash = devt_hash_func,
diff --git a/src/basic/log.c b/src/basic/log.c
index b96afc4de4..e6d7d15182 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -340,10 +340,10 @@ static int write_to_console(
}
if (highlight)
- IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
+ IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED);
IOVEC_SET_STRING(iovec[n++], buffer);
if (highlight)
- IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
+ IOVEC_SET_STRING(iovec[n++], ANSI_NORMAL);
IOVEC_SET_STRING(iovec[n++], "\n");
if (writev(console_fd, iovec, n) < 0) {
@@ -922,7 +922,7 @@ int log_set_max_level_from_string(const char *e) {
t = log_level_from_string(e);
if (t < 0)
- return t;
+ return -EINVAL;
log_set_max_level(t);
return 0;
diff --git a/src/basic/log.h b/src/basic/log.h
index 569762d083..369d6b1127 100644
--- a/src/basic/log.h
+++ b/src/basic/log.h
@@ -227,3 +227,15 @@ int log_syntax_internal(
? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
: -abs(_e); \
})
+
+#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \
+ ({ \
+ int _level = (level); \
+ if (log_get_max_level() >= LOG_PRI(_level)) { \
+ _cleanup_free_ char *_p = NULL; \
+ _p = utf8_escape_invalid(rvalue); \
+ log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \
+ "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \
+ } \
+ -EINVAL; \
+ })
diff --git a/src/basic/macro.h b/src/basic/macro.h
index cbc3ca97b8..f55d65e2f1 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -123,8 +123,11 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL));
}
-#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
-
+#define ELEMENTSOF(x) \
+ __extension__ (__builtin_choose_expr( \
+ !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \
+ sizeof(x)/sizeof((x)[0]), \
+ (void)0))
/*
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
@@ -213,18 +216,20 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
(__x / __y + !!(__x % __y)); \
})
-#define assert_se(expr) \
+#define assert_message_se(expr, message) \
do { \
if (_unlikely_(!(expr))) \
- log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
- } while (false) \
+ log_assert_failed(message, __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ } while (false)
+
+#define assert_se(expr) assert_message_se(expr, #expr)
/* We override the glibc assert() here. */
#undef assert
#ifdef NDEBUG
#define assert(expr) do {} while(false)
#else
-#define assert(expr) assert_se(expr)
+#define assert(expr) assert_message_se(expr, #expr)
#endif
#define assert_not_reached(t) \
@@ -249,19 +254,19 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
REENABLE_WARNING
#endif
-#define assert_log(expr) ((_likely_(expr)) \
- ? (true) \
- : (log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__), false))
+#define assert_log(expr, message) ((_likely_(expr)) \
+ ? (true) \
+ : (log_assert_failed_return(message, __FILE__, __LINE__, __PRETTY_FUNCTION__), false))
#define assert_return(expr, r) \
do { \
- if (!assert_log(expr)) \
+ if (!assert_log(expr, #expr)) \
return (r); \
} while (false)
#define assert_return_errno(expr, r, err) \
do { \
- if (!assert_log(expr)) { \
+ if (!assert_log(expr, #expr)) { \
errno = err; \
return (r); \
} \
@@ -465,18 +470,6 @@ do { \
#define GID_INVALID ((gid_t) -1)
#define MODE_INVALID ((mode_t) -1)
-static inline bool UID_IS_INVALID(uid_t uid) {
- /* We consider both the old 16bit -1 user and the newer 32bit
- * -1 user invalid, since they are or used to be incompatible
- * with syscalls such as setresuid() or chown(). */
-
- return uid == (uid_t) ((uint32_t) -1) || uid == (uid_t) ((uint16_t) -1);
-}
-
-static inline bool GID_IS_INVALID(gid_t gid) {
- return gid == (gid_t) ((uint32_t) -1) || gid == (gid_t) ((uint16_t) -1);
-}
-
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \
diff --git a/src/basic/missing.h b/src/basic/missing.h
index dc1f244d4c..59e835a466 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -139,6 +139,8 @@ static inline int pivot_root(const char *new_root, const char *put_old) {
# define __NR_memfd_create 385
# elif defined __aarch64__
# define __NR_memfd_create 279
+# elif defined __s390__
+# define __NR_memfd_create 350
# elif defined _MIPS_SIM
# if _MIPS_SIM == _MIPS_SIM_ABI32
# define __NR_memfd_create 4354
@@ -840,6 +842,19 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
#endif
+#if !HAVE_DECL_IFLA_BR_PRIORITY
+#define IFLA_BR_UNSPEC 0
+#define IFLA_BR_FORWARD_DELAY 1
+#define IFLA_BR_HELLO_TIME 2
+#define IFLA_BR_MAX_AGE 3
+#define IFLA_BR_AGEING_TIME 4
+#define IFLA_BR_STP_STATE 5
+#define IFLA_BR_PRIORITY 6
+#define __IFLA_BR_MAX 7
+
+#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
+#endif
+
#if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC
#define IFLA_BRPORT_UNSPEC 0
#define IFLA_BRPORT_STATE 1
@@ -1028,7 +1043,12 @@ static inline int renameat2(int oldfd, const char *oldname, int newfd, const cha
#if !HAVE_DECL_KCMP
static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
+#if defined(__NR_kcmp)
return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
}
#endif
@@ -1043,3 +1063,48 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns
#ifndef INPUT_PROP_ACCELEROMETER
#define INPUT_PROP_ACCELEROMETER 0x06
#endif
+
+#if !HAVE_DECL_KEY_SERIAL_T
+typedef int32_t key_serial_t;
+#endif
+
+#if !HAVE_DECL_KEYCTL
+static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) {
+#if defined(__NR_keyctl)
+ return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) {
+#if defined (__NR_add_key)
+ return syscall(__NR_add_key, type, description, payload, plen, ringid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+static inline key_serial_t request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) {
+#if defined (__NR_request_key)
+ return syscall(__NR_request_key, type, description, callout_info, destringid);
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif
+
+#ifndef KEYCTL_READ
+#define KEYCTL_READ 11
+#endif
+
+#ifndef KEYCTL_SET_TIMEOUT
+#define KEYCTL_SET_TIMEOUT 15
+#endif
+
+#ifndef KEY_SPEC_USER_KEYRING
+#define KEY_SPEC_USER_KEYRING -4
+#endif
diff --git a/src/basic/prioq.c b/src/basic/prioq.c
index b89888be0e..d55b348c22 100644
--- a/src/basic/prioq.c
+++ b/src/basic/prioq.c
@@ -19,6 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+/*
+ * Priority Queue
+ * The prioq object implements a priority queue. That is, it orders objects by
+ * their priority and allows O(1) access to the object with the highest
+ * priority. Insertion and removal are Θ(log n). Optionally, the caller can
+ * provide a pointer to an index which will be kept up-to-date by the prioq.
+ *
+ * The underlying algorithm used in this implementation is a Heap.
+ */
+
#include "util.h"
#include "prioq.h"
@@ -101,7 +111,7 @@ static unsigned shuffle_up(Prioq *q, unsigned idx) {
k = (idx-1)/2;
- if (q->compare_func(q->items[k].data, q->items[idx].data) < 0)
+ if (q->compare_func(q->items[k].data, q->items[idx].data) <= 0)
break;
swap(q, idx, k);
diff --git a/src/basic/process-util.c b/src/basic/process-util.c
index cff2d2a034..d8a94a4572 100644
--- a/src/basic/process-util.c
+++ b/src/basic/process-util.c
@@ -215,7 +215,7 @@ int get_process_capeff(pid_t pid, char **capeff) {
p = procfs_file_alloca(pid, "status");
- r = get_status_field(p, "\nCapEff:", capeff);
+ r = get_proc_field(p, "CapEff", WHITESPACE, capeff);
if (r == -ENOENT)
return -ESRCH;
diff --git a/src/basic/ring.c b/src/basic/ring.c
deleted file mode 100644
index 6814918464..0000000000
--- a/src/basic/ring.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/uio.h>
-#include "macro.h"
-#include "ring.h"
-
-#define RING_MASK(_r, _v) ((_v) & ((_r)->size - 1))
-
-void ring_flush(Ring *r) {
- assert(r);
-
- r->start = 0;
- r->used = 0;
-}
-
-void ring_clear(Ring *r) {
- assert(r);
-
- free(r->buf);
- zero(*r);
-}
-
-/*
- * Get data pointers for current ring-buffer data. @vec must be an array of 2
- * iovec objects. They are filled according to the data available in the
- * ring-buffer. 0, 1 or 2 is returned according to the number of iovec objects
- * that were filled (0 meaning buffer is empty).
- *
- * Hint: "struct iovec" is defined in <sys/uio.h> and looks like this:
- * struct iovec {
- * void *iov_base;
- * size_t iov_len;
- * };
- */
-size_t ring_peek(Ring *r, struct iovec *vec) {
- assert(r);
-
- if (r->used == 0) {
- return 0;
- } else if (r->start + r->used <= r->size) {
- if (vec) {
- vec[0].iov_base = &r->buf[r->start];
- vec[0].iov_len = r->used;
- }
- return 1;
- } else {
- if (vec) {
- vec[0].iov_base = &r->buf[r->start];
- vec[0].iov_len = r->size - r->start;
- vec[1].iov_base = r->buf;
- vec[1].iov_len = r->used - (r->size - r->start);
- }
- return 2;
- }
-}
-
-/*
- * Copy data from the ring buffer into the linear external buffer @buf. Copy
- * at most @size bytes. If the ring buffer size is smaller, copy less bytes and
- * return the number of bytes copied.
- */
-size_t ring_copy(Ring *r, void *buf, size_t size) {
- size_t l;
-
- assert(r);
- assert(buf);
-
- if (size > r->used)
- size = r->used;
-
- if (size > 0) {
- l = r->size - r->start;
- if (size <= l) {
- memcpy(buf, &r->buf[r->start], size);
- } else {
- memcpy(buf, &r->buf[r->start], l);
- memcpy((uint8_t*)buf + l, r->buf, size - l);
- }
- }
-
- return size;
-}
-
-/*
- * Resize ring-buffer to size @nsize. @nsize must be a power-of-2, otherwise
- * ring operations will behave incorrectly.
- */
-static int ring_resize(Ring *r, size_t nsize) {
- uint8_t *buf;
- size_t l;
-
- assert(r);
- assert(nsize > 0);
-
- buf = malloc(nsize);
- if (!buf)
- return -ENOMEM;
-
- if (r->used > 0) {
- l = r->size - r->start;
- if (r->used <= l) {
- memcpy(buf, &r->buf[r->start], r->used);
- } else {
- memcpy(buf, &r->buf[r->start], l);
- memcpy(&buf[l], r->buf, r->used - l);
- }
- }
-
- free(r->buf);
- r->buf = buf;
- r->size = nsize;
- r->start = 0;
-
- return 0;
-}
-
-/*
- * Resize ring-buffer to provide enough room for @add bytes of new data. This
- * resizes the buffer if it is too small. It returns -ENOMEM on OOM and 0 on
- * success.
- */
-static int ring_grow(Ring *r, size_t add) {
- size_t need;
-
- assert(r);
-
- if (r->size - r->used >= add)
- return 0;
-
- need = r->used + add;
- if (need <= r->used)
- return -ENOMEM;
- else if (need < 4096)
- need = 4096;
-
- need = ALIGN_POWER2(need);
- if (need == 0)
- return -ENOMEM;
-
- return ring_resize(r, need);
-}
-
-/*
- * Push @len bytes from @u8 into the ring buffer. The buffer is resized if it
- * is too small. -ENOMEM is returned on OOM, 0 on success.
- */
-int ring_push(Ring *r, const void *u8, size_t size) {
- int err;
- size_t pos, l;
-
- assert(r);
- assert(u8);
-
- if (size == 0)
- return 0;
-
- err = ring_grow(r, size);
- if (err < 0)
- return err;
-
- pos = RING_MASK(r, r->start + r->used);
- l = r->size - pos;
- if (l >= size) {
- memcpy(&r->buf[pos], u8, size);
- } else {
- memcpy(&r->buf[pos], u8, l);
- memcpy(r->buf, (const uint8_t*)u8 + l, size - l);
- }
-
- r->used += size;
-
- return 0;
-}
-
-/*
- * Remove @len bytes from the start of the ring-buffer. Note that we protect
- * against overflows so removing more bytes than available is safe.
- */
-void ring_pull(Ring *r, size_t size) {
- assert(r);
-
- if (size > r->used)
- size = r->used;
-
- r->start = RING_MASK(r, r->start + size);
- r->used -= size;
-}
diff --git a/src/basic/ring.h b/src/basic/ring.h
deleted file mode 100644
index dbd6296384..0000000000
--- a/src/basic/ring.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-
-typedef struct Ring Ring;
-
-struct Ring {
- uint8_t *buf; /* buffer or NULL */
- size_t size; /* actual size of @buf */
- size_t start; /* start position of ring */
- size_t used; /* number of actually used bytes */
-};
-
-/* flush buffer so it is empty again */
-void ring_flush(Ring *r);
-
-/* flush buffer, free allocated data and reset to initial state */
-void ring_clear(Ring *r);
-
-/* get pointers to buffer data and their length */
-size_t ring_peek(Ring *r, struct iovec *vec);
-
-/* copy data into external linear buffer */
-size_t ring_copy(Ring *r, void *buf, size_t size);
-
-/* push data to the end of the buffer */
-int ring_push(Ring *r, const void *u8, size_t size);
-
-/* pull data from the front of the buffer */
-void ring_pull(Ring *r, size_t size);
-
-/* return size of occupied buffer in bytes */
-static inline size_t ring_get_size(Ring *r) {
- return r->used;
-}
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
index a39a0f775a..747e6f4dbb 100644
--- a/src/basic/selinux-util.c
+++ b/src/basic/selinux-util.c
@@ -295,14 +295,20 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
return r;
}
-void mac_selinux_free(char *label) {
+char* mac_selinux_free(char *label) {
#ifdef HAVE_SELINUX
+ if (!label)
+ return NULL;
+
if (!mac_selinux_use())
- return;
+ return NULL;
+
freecon((security_context_t) label);
#endif
+
+ return NULL;
}
int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h
index 8467185291..2afcaec183 100644
--- a/src/basic/selinux-util.h
+++ b/src/basic/selinux-util.h
@@ -24,6 +24,8 @@
#include <sys/socket.h>
#include <stdbool.h>
+#include "macro.h"
+
bool mac_selinux_use(void);
void mac_selinux_retest(void);
@@ -36,7 +38,7 @@ int mac_selinux_apply(const char *path, const char *label);
int mac_selinux_get_create_label_from_exe(const char *exe, char **label);
int mac_selinux_get_our_label(char **label);
int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label);
-void mac_selinux_free(char *label);
+char* mac_selinux_free(char *label);
int mac_selinux_create_file_prepare(const char *path, mode_t mode);
void mac_selinux_create_file_clear(void);
@@ -45,3 +47,5 @@ int mac_selinux_create_socket_prepare(const char *label);
void mac_selinux_create_socket_clear(void);
int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(char*, mac_selinux_free);
diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c
index f68bd283a1..3b61961389 100644
--- a/src/basic/siphash24.c
+++ b/src/basic/siphash24.c
@@ -13,123 +13,170 @@
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
(Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd)
+ (Refactored by Tom Gundersen to split up in several functions and follow systemd
+ coding style)
*/
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
+
+#include "sparse-endian.h"
#include "siphash24.h"
+#include "util.h"
-typedef uint64_t u64;
-typedef uint32_t u32;
-typedef uint8_t u8;
-
-#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) )
-
-#define U32TO8_LE(p, v) \
- (p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \
- (p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24);
-
-#define U64TO8_LE(p, v) \
- U32TO8_LE((p), (u32)((v) )); \
- U32TO8_LE((p) + 4, (u32)((v) >> 32));
-
-#define U8TO64_LE(p) \
- (((u64)((p)[0]) ) | \
- ((u64)((p)[1]) << 8) | \
- ((u64)((p)[2]) << 16) | \
- ((u64)((p)[3]) << 24) | \
- ((u64)((p)[4]) << 32) | \
- ((u64)((p)[5]) << 40) | \
- ((u64)((p)[6]) << 48) | \
- ((u64)((p)[7]) << 56))
-
-#define SIPROUND \
- do { \
- v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
- v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \
- v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \
- v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
- } while(0)
+static inline uint64_t rotate_left(uint64_t x, uint8_t b) {
+ assert(b < 64);
+
+ return (x << b) | (x >> (64 - b));
+}
+
+static inline void sipround(struct siphash *state) {
+ assert(state);
+
+ state->v0 += state->v1;
+ state->v1 = rotate_left(state->v1, 13);
+ state->v1 ^= state->v0;
+ state->v0 = rotate_left(state->v0, 32);
+ state->v2 += state->v3;
+ state->v3 = rotate_left(state->v3, 16);
+ state->v3 ^= state->v2;
+ state->v0 += state->v3;
+ state->v3 = rotate_left(state->v3, 21);
+ state->v3 ^= state->v0;
+ state->v2 += state->v1;
+ state->v1 = rotate_left(state->v1, 17);
+ state->v1 ^= state->v2;
+ state->v2 = rotate_left(state->v2, 32);
+}
+
+void siphash24_init(struct siphash *state, const uint8_t k[16]) {
+ uint64_t k0, k1;
+
+ assert(state);
+ assert(k);
+
+ k0 = le64toh(*(le64_t*) k);
+ k1 = le64toh(*(le64_t*) (k + 8));
+
+ /* "somepseudorandomlygeneratedbytes" */
+ state->v0 = 0x736f6d6570736575ULL ^ k0;
+ state->v1 = 0x646f72616e646f6dULL ^ k1;
+ state->v2 = 0x6c7967656e657261ULL ^ k0;
+ state->v3 = 0x7465646279746573ULL ^ k1;
+ state->padding = 0;
+ state->inlen = 0;
+}
+
+void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) {
+ uint64_t m;
+ const uint8_t *in = _in;
+ const uint8_t *end = in + inlen;
+ unsigned left = state->inlen & 7;
+
+ assert(in);
+ assert(state);
+
+ /* update total length */
+ state->inlen += inlen;
+
+ /* if padding exists, fill it out */
+ if (left > 0) {
+ for ( ; in < end && left < 8; in ++, left ++ )
+ state->padding |= ( ( uint64_t )*in ) << (left * 8);
+
+ if (in == end && left < 8)
+ /* we did not have enough input to fill out the padding completely */
+ return;
-/* SipHash-2-4 */
-void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16])
-{
- /* "somepseudorandomlygeneratedbytes" */
- u64 v0 = 0x736f6d6570736575ULL;
- u64 v1 = 0x646f72616e646f6dULL;
- u64 v2 = 0x6c7967656e657261ULL;
- u64 v3 = 0x7465646279746573ULL;
- u64 b;
- u64 k0 = U8TO64_LE( k );
- u64 k1 = U8TO64_LE( k + 8 );
- u64 m;
- const u8 *in = _in;
- const u8 *end = in + inlen - ( inlen % sizeof( u64 ) );
- const int left = inlen & 7;
- b = ( ( u64 )inlen ) << 56;
- v3 ^= k1;
- v2 ^= k0;
- v1 ^= k1;
- v0 ^= k0;
-
- for ( ; in != end; in += 8 )
- {
- m = U8TO64_LE( in );
#ifdef DEBUG
- printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
- printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
- printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
- printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
- printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m );
+ printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
+ printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
+ printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
+ printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
+ printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding);
#endif
- v3 ^= m;
- SIPROUND;
- SIPROUND;
- v0 ^= m;
- }
+ state->v3 ^= state->padding;
+ sipround(state);
+ sipround(state);
+ state->v0 ^= state->padding;
- switch( left )
- {
- case 7: b |= ( ( u64 )in[ 6] ) << 48;
+ state->padding = 0;
+ }
- case 6: b |= ( ( u64 )in[ 5] ) << 40;
+ end -= ( state->inlen % sizeof (uint64_t) );
- case 5: b |= ( ( u64 )in[ 4] ) << 32;
+ for ( ; in < end; in += 8 ) {
+ m = le64toh(*(le64_t*) in);
+#ifdef DEBUG
+ printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
+ printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
+ printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
+ printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
+ printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m);
+#endif
+ state->v3 ^= m;
+ sipround(state);
+ sipround(state);
+ state->v0 ^= m;
+ }
+
+ left = state->inlen & 7;
+
+ switch(left)
+ {
+ case 7: state->padding |= ((uint64_t) in[6]) << 48;
- case 4: b |= ( ( u64 )in[ 3] ) << 24;
+ case 6: state->padding |= ((uint64_t) in[5]) << 40;
- case 3: b |= ( ( u64 )in[ 2] ) << 16;
+ case 5: state->padding |= ((uint64_t) in[4]) << 32;
- case 2: b |= ( ( u64 )in[ 1] ) << 8;
+ case 4: state->padding |= ((uint64_t) in[3]) << 24;
- case 1: b |= ( ( u64 )in[ 0] ); break;
+ case 3: state->padding |= ((uint64_t) in[2]) << 16;
+
+ case 2: state->padding |= ((uint64_t) in[1]) << 8;
+
+ case 1: state->padding |= ((uint64_t) in[0]); break;
+
+ case 0: break;
+ }
+}
- case 0: break;
- }
+void siphash24_finalize(uint8_t out[8], struct siphash *state) {
+ uint64_t b;
+ b = state->padding | (( ( uint64_t )state->inlen ) << 56);
#ifdef DEBUG
- printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
- printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
- printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
- printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
- printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b );
+ printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t)state->v0);
+ printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t)state->v1);
+ printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t)state->v2);
+ printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t)state->v3);
+ printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding);
#endif
- v3 ^= b;
- SIPROUND;
- SIPROUND;
- v0 ^= b;
+ state->v3 ^= b;
+ sipround(state);
+ sipround(state);
+ state->v0 ^= b;
+
#ifdef DEBUG
- printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 );
- printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 );
- printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 );
- printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 );
+ printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0);
+ printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1);
+ printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2);
+ printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3);
#endif
- v2 ^= 0xff;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- SIPROUND;
- b = v0 ^ v1 ^ v2 ^ v3;
- U64TO8_LE( out, b );
+ state->v2 ^= 0xff;
+
+ sipround(state);
+ sipround(state);
+ sipround(state);
+ sipround(state);
+
+ *(le64_t*)out = htole64(state->v0 ^ state->v1 ^ state->v2 ^ state->v3);
+}
+
+/* SipHash-2-4 */
+void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) {
+ struct siphash state;
+
+ siphash24_init(&state, k);
+ siphash24_compress(_in, inlen, &state);
+ siphash24_finalize(out, &state);
}
diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h
index 62e1168a79..6c5cd98ee8 100644
--- a/src/basic/siphash24.h
+++ b/src/basic/siphash24.h
@@ -3,4 +3,17 @@
#include <inttypes.h>
#include <sys/types.h>
+struct siphash {
+ uint64_t v0;
+ uint64_t v1;
+ uint64_t v2;
+ uint64_t v3;
+ uint64_t padding;
+ size_t inlen;
+};
+
+void siphash24_init(struct siphash *state, const uint8_t k[16]);
+void siphash24_compress(const void *in, size_t inlen, struct siphash *state);
+void siphash24_finalize(uint8_t out[8], struct siphash *state);
+
void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]);
diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c
index 9e221d6eab..5f570ff02a 100644
--- a/src/basic/smack-util.c
+++ b/src/basic/smack-util.c
@@ -29,9 +29,6 @@
#include "fileio.h"
#include "smack-util.h"
-#define SMACK_FLOOR_LABEL "_"
-#define SMACK_STAR_LABEL "*"
-
#ifdef HAVE_SMACK
bool mac_smack_use(void) {
static int cached_use = -1;
diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h
index b3aa55eb8a..e756dc8c28 100644
--- a/src/basic/smack-util.h
+++ b/src/basic/smack-util.h
@@ -27,6 +27,9 @@
#include "macro.h"
+#define SMACK_FLOOR_LABEL "_"
+#define SMACK_STAR_LABEL "*"
+
typedef enum SmackAttr {
SMACK_ATTR_ACCESS = 0,
SMACK_ATTR_EXEC = 1,
diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c
index 144e6fd86e..937124cc02 100644
--- a/src/basic/socket-label.c
+++ b/src/basic/socket-label.c
@@ -146,11 +146,8 @@ int make_socket_fd(int log_level, const char* address, int flags) {
int fd, r;
r = socket_address_parse(&a, address);
- if (r < 0) {
- log_error("Failed to parse socket address \"%s\": %s",
- address, strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address);
fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT,
NULL, false, false, false, 0755, 0644, NULL);
diff --git a/src/basic/strv.c b/src/basic/strv.c
index b9aef64b15..b66c176487 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -188,17 +188,48 @@ char **strv_new(const char *x, ...) {
return r;
}
-int strv_extend_strv(char ***a, char **b) {
- int r;
- char **s;
+int strv_extend_strv(char ***a, char **b, bool filter_duplicates) {
+ char **s, **t;
+ size_t p, q, i = 0, j;
+
+ assert(a);
+
+ if (strv_isempty(b))
+ return 0;
+
+ p = strv_length(*a);
+ q = strv_length(b);
+
+ t = realloc(*a, sizeof(char*) * (p + q + 1));
+ if (!t)
+ return -ENOMEM;
+
+ t[p] = NULL;
+ *a = t;
STRV_FOREACH(s, b) {
- r = strv_extend(a, *s);
- if (r < 0)
- return r;
+
+ if (filter_duplicates && strv_contains(t, *s))
+ continue;
+
+ t[p+i] = strdup(*s);
+ if (!t[p+i])
+ goto rollback;
+
+ i++;
+ t[p+i] = NULL;
}
- return 0;
+ assert(i <= q);
+
+ return (int) i;
+
+rollback:
+ for (j = 0; j < i; j++)
+ free(t[p + j]);
+
+ t[p] = NULL;
+ return -ENOMEM;
}
int strv_extend_strv_concat(char ***a, char **b, const char *suffix) {
@@ -277,8 +308,8 @@ char **strv_split_newlines(const char *s) {
}
int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) {
- size_t n = 0, allocated = 0;
_cleanup_strv_free_ char **l = NULL;
+ size_t n = 0, allocated = 0;
int r;
assert(t);
@@ -302,13 +333,16 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract
l[n] = NULL;
}
- if (!l)
+ if (!l) {
l = new0(char*, 1);
+ if (!l)
+ return -ENOMEM;
+ }
*t = l;
l = NULL;
- return 0;
+ return (int) n;
}
char *strv_join(char **l, const char *separator) {
@@ -615,6 +649,41 @@ char **strv_split_nulstr(const char *s) {
return r;
}
+int strv_make_nulstr(char **l, char **p, size_t *q) {
+ size_t n_allocated = 0, n = 0;
+ _cleanup_free_ char *m = NULL;
+ char **i;
+
+ assert(p);
+ assert(q);
+
+ STRV_FOREACH(i, l) {
+ size_t z;
+
+ z = strlen(*i);
+
+ if (!GREEDY_REALLOC(m, n_allocated, n + z + 1))
+ return -ENOMEM;
+
+ memcpy(m + n, *i, z + 1);
+ n += z + 1;
+ }
+
+ if (!m) {
+ m = new0(char, 1);
+ if (!m)
+ return -ENOMEM;
+ n = 0;
+ }
+
+ *p = m;
+ *q = n;
+
+ m = NULL;
+
+ return 0;
+}
+
bool strv_overlap(char **a, char **b) {
char **i;
@@ -641,8 +710,12 @@ char **strv_sort(char **l) {
}
bool strv_equal(char **a, char **b) {
- if (!a || !b)
- return a == b;
+
+ if (strv_isempty(a))
+ return strv_isempty(b);
+
+ if (strv_isempty(b))
+ return false;
for ( ; *a || *b; ++a, ++b)
if (!streq_ptr(*a, *b))
@@ -720,3 +793,66 @@ bool strv_fnmatch(char* const* patterns, const char *s, int flags) {
return false;
}
+
+char ***strv_free_free(char ***l) {
+ char ***i;
+
+ if (!l)
+ return NULL;
+
+ for (i = l; *i; i++)
+ strv_free(*i);
+
+ free(l);
+ return NULL;
+}
+
+char **strv_skip(char **l, size_t n) {
+
+ while (n > 0) {
+ if (strv_isempty(l))
+ return l;
+
+ l++, n--;
+ }
+
+ return l;
+}
+
+int strv_extend_n(char ***l, const char *value, size_t n) {
+ size_t i, j, k;
+ char **nl;
+
+ assert(l);
+
+ if (!value)
+ return 0;
+ if (n == 0)
+ return 0;
+
+ /* Adds the value value n times to l */
+
+ k = strv_length(*l);
+
+ nl = realloc(*l, sizeof(char*) * (k + n + 1));
+ if (!nl)
+ return -ENOMEM;
+
+ *l = nl;
+
+ for (i = k; i < k + n; i++) {
+ nl[i] = strdup(value);
+ if (!nl[i])
+ goto rollback;
+ }
+
+ nl[i] = NULL;
+ return 0;
+
+rollback:
+ for (j = k; j < i; j++)
+ free(nl[j]);
+
+ nl[k] = NULL;
+ return -ENOMEM;
+}
diff --git a/src/basic/strv.h b/src/basic/strv.h
index f07da8cdf3..e49f443835 100644
--- a/src/basic/strv.h
+++ b/src/basic/strv.h
@@ -40,7 +40,7 @@ void strv_clear(char **l);
char **strv_copy(char * const *l);
unsigned strv_length(char * const *l) _pure_;
-int strv_extend_strv(char ***a, char **b);
+int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
int strv_extend(char ***l, const char *value);
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
@@ -80,6 +80,7 @@ char *strv_join_quoted(char **l);
char **strv_parse_nulstr(const char *s, size_t l);
char **strv_split_nulstr(const char *s);
+int strv_make_nulstr(char **l, char **p, size_t *n);
bool strv_overlap(char **a, char **b) _pure_;
@@ -154,3 +155,9 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i
return strv_isempty(patterns) ||
strv_fnmatch(patterns, s, flags);
}
+
+char ***strv_free_free(char ***l);
+
+char **strv_skip(char **l, size_t n);
+
+int strv_extend_n(char ***l, const char *value, size_t n);
diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c
index c5ef5ab0d1..ca7554a9fa 100644
--- a/src/basic/terminal-util.c
+++ b/src/basic/terminal-util.c
@@ -48,7 +48,7 @@ int chvt(int vt) {
if (fd < 0)
return -errno;
- if (vt < 0) {
+ if (vt <= 0) {
int tiocl[2] = {
TIOCL_GETKMSGREDIRECT,
0
@@ -139,14 +139,14 @@ int ask_char(char *ret, const char *replies, const char *text, ...) {
bool need_nl = true;
if (on_tty())
- fputs(ANSI_HIGHLIGHT_ON, stdout);
+ fputs(ANSI_HIGHLIGHT, stdout);
va_start(ap, text);
vprintf(text, ap);
va_end(ap);
if (on_tty())
- fputs(ANSI_HIGHLIGHT_OFF, stdout);
+ fputs(ANSI_NORMAL, stdout);
fflush(stdout);
@@ -183,14 +183,14 @@ int ask_string(char **ret, const char *text, ...) {
va_list ap;
if (on_tty())
- fputs(ANSI_HIGHLIGHT_ON, stdout);
+ fputs(ANSI_HIGHLIGHT, stdout);
va_start(ap, text);
vprintf(text, ap);
va_end(ap);
if (on_tty())
- fputs(ANSI_HIGHLIGHT_OFF, stdout);
+ fputs(ANSI_NORMAL, stdout);
fflush(stdout);
@@ -480,10 +480,6 @@ int acquire_terminal(
safe_close(notify);
- r = reset_terminal_fd(fd, true);
- if (r < 0)
- log_warning_errno(r, "Failed to reset terminal: %m");
-
return fd;
fail:
@@ -539,8 +535,9 @@ int terminal_vhangup(const char *name) {
}
int vt_disallocate(const char *name) {
- int fd, r;
+ _cleanup_close_ int fd = -1;
unsigned u;
+ int r;
/* Deallocate the VT if possible. If not possible
* (i.e. because it is the active one), at least clear it
@@ -562,8 +559,6 @@ int vt_disallocate(const char *name) {
"\033[H" /* move home */
"\033[2J", /* clear screen */
10, false);
- safe_close(fd);
-
return 0;
}
@@ -583,7 +578,7 @@ int vt_disallocate(const char *name) {
return fd;
r = ioctl(fd, VT_DISALLOCATE, u);
- safe_close(fd);
+ fd = safe_close(fd);
if (r >= 0)
return 0;
@@ -602,32 +597,9 @@ int vt_disallocate(const char *name) {
"\033[H" /* move home */
"\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
10, false);
- safe_close(fd);
-
return 0;
}
-void warn_melody(void) {
- _cleanup_close_ int fd = -1;
-
- fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return;
-
- /* Yeah, this is synchronous. Kinda sucks. But well... */
-
- (void) ioctl(fd, KIOCSOUND, (int)(1193180/440));
- usleep(125*USEC_PER_MSEC);
-
- (void) ioctl(fd, KIOCSOUND, (int)(1193180/220));
- usleep(125*USEC_PER_MSEC);
-
- (void) ioctl(fd, KIOCSOUND, (int)(1193180/220));
- usleep(125*USEC_PER_MSEC);
-
- (void) ioctl(fd, KIOCSOUND, 0);
-}
-
int make_console_stdio(void) {
int fd, r;
@@ -637,6 +609,10 @@ int make_console_stdio(void) {
if (fd < 0)
return log_error_errno(fd, "Failed to acquire terminal: %m");
+ r = reset_terminal_fd(fd, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
+
r = make_stdio(fd);
if (r < 0)
return log_error_errno(r, "Failed to duplicate terminal fd: %m");
@@ -1075,6 +1051,33 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) {
return 0;
}
+int ptsname_malloc(int fd, char **ret) {
+ size_t l = 100;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ for (;;) {
+ char *c;
+
+ c = new(char, l);
+ if (!c)
+ return -ENOMEM;
+
+ if (ptsname_r(fd, c, l) == 0) {
+ *ret = c;
+ return 0;
+ }
+ if (errno != ERANGE) {
+ free(c);
+ return -errno;
+ }
+
+ free(c);
+ l *= 2;
+ }
+}
+
int ptsname_namespace(int pty, char **ret) {
int no = -1, r;
@@ -1093,3 +1096,104 @@ int ptsname_namespace(int pty, char **ret) {
return 0;
}
+
+int openpt_in_namespace(pid_t pid, int flags) {
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ siginfo_t si;
+ pid_t child;
+ int r;
+
+ assert(pid > 0);
+
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+ if (r < 0)
+ return r;
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+ return -errno;
+
+ child = fork();
+ if (child < 0)
+ return -errno;
+
+ if (child == 0) {
+ int master;
+
+ pair[0] = safe_close(pair[0]);
+
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
+ if (master < 0)
+ _exit(EXIT_FAILURE);
+
+ if (unlockpt(master) < 0)
+ _exit(EXIT_FAILURE);
+
+ if (send_one_fd(pair[1], master, 0) < 0)
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ pair[1] = safe_close(pair[1]);
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0)
+ return r;
+ if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
+ return -EIO;
+
+ return receive_one_fd(pair[0], 0);
+}
+
+int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ siginfo_t si;
+ pid_t child;
+ int r;
+
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+ if (r < 0)
+ return r;
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+ return -errno;
+
+ child = fork();
+ if (child < 0)
+ return -errno;
+
+ if (child == 0) {
+ int master;
+
+ pair[0] = safe_close(pair[0]);
+
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC);
+ if (master < 0)
+ _exit(EXIT_FAILURE);
+
+ if (send_one_fd(pair[1], master, 0) < 0)
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ pair[1] = safe_close(pair[1]);
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0)
+ return r;
+ if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
+ return -EIO;
+
+ return receive_one_fd(pair[0], 0);
+}
diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h
index b9a3809a6c..ee0b68b433 100644
--- a/src/basic/terminal-util.h
+++ b/src/basic/terminal-util.h
@@ -26,16 +26,22 @@
#include "macro.h"
#include "time-util.h"
-#define ANSI_HIGHLIGHT_ON "\x1B[1;39m"
-#define ANSI_RED_ON "\x1B[31m"
-#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m"
-#define ANSI_GREEN_ON "\x1B[32m"
-#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m"
-#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m"
-#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m"
-#define ANSI_HIGHLIGHT_OFF "\x1B[0m"
+#define ANSI_RED "\x1B[0;31m"
+#define ANSI_GREEN "\x1B[0;32m"
+#define ANSI_UNDERLINE "\x1B[0;4m"
+#define ANSI_HIGHLIGHT "\x1B[0;1;39m"
+#define ANSI_HIGHLIGHT_RED "\x1B[0;1;31m"
+#define ANSI_HIGHLIGHT_GREEN "\x1B[0;1;32m"
+#define ANSI_HIGHLIGHT_YELLOW "\x1B[0;1;33m"
+#define ANSI_HIGHLIGHT_BLUE "\x1B[0;1;34m"
+#define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m"
+#define ANSI_NORMAL "\x1B[0m"
+
#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K"
+/* Set cursor to top left corner and clear screen */
+#define ANSI_HOME_CLEAR "\x1B[H\x1B[2J"
+
int reset_terminal_fd(int fd, bool switch_to_text);
int reset_terminal(const char *name);
@@ -61,8 +67,6 @@ bool tty_is_console(const char *tty) _pure_;
int vtnr_from_tty(const char *tty);
const char *default_term_for_tty(const char *tty);
-void warn_melody(void);
-
int make_stdio(int fd);
int make_null_stdio(void);
int make_console_stdio(void);
@@ -78,28 +82,36 @@ void columns_lines_cache_reset(int _unused_ signum);
bool on_tty(void);
+static inline const char *ansi_underline(void) {
+ return on_tty() ? ANSI_UNDERLINE : "";
+}
+
static inline const char *ansi_highlight(void) {
- return on_tty() ? ANSI_HIGHLIGHT_ON : "";
+ return on_tty() ? ANSI_HIGHLIGHT : "";
+}
+
+static inline const char *ansi_highlight_underline(void) {
+ return on_tty() ? ANSI_HIGHLIGHT_UNDERLINE : "";
}
static inline const char *ansi_highlight_red(void) {
- return on_tty() ? ANSI_HIGHLIGHT_RED_ON : "";
+ return on_tty() ? ANSI_HIGHLIGHT_RED : "";
}
static inline const char *ansi_highlight_green(void) {
- return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : "";
+ return on_tty() ? ANSI_HIGHLIGHT_GREEN : "";
}
static inline const char *ansi_highlight_yellow(void) {
- return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : "";
+ return on_tty() ? ANSI_HIGHLIGHT_YELLOW : "";
}
static inline const char *ansi_highlight_blue(void) {
- return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : "";
+ return on_tty() ? ANSI_HIGHLIGHT_BLUE : "";
}
-static inline const char *ansi_highlight_off(void) {
- return on_tty() ? ANSI_HIGHLIGHT_OFF : "";
+static inline const char *ansi_normal(void) {
+ return on_tty() ? ANSI_NORMAL : "";
}
int get_ctty_devnr(pid_t pid, dev_t *d);
@@ -108,4 +120,8 @@ int get_ctty(pid_t, dev_t *_devnr, char **r);
int getttyname_malloc(int fd, char **r);
int getttyname_harder(int fd, char **r);
+int ptsname_malloc(int fd, char **ret);
int ptsname_namespace(int pty, char **ret);
+
+int openpt_in_namespace(pid_t pid, int flags);
+int open_terminal_in_namespace(pid_t pid, const char *name, int mode);
diff --git a/src/basic/time-util.c b/src/basic/time-util.c
index 531931f6e1..d4e0914b27 100644
--- a/src/basic/time-util.c
+++ b/src/basic/time-util.c
@@ -19,7 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <time.h>
#include <string.h>
#include <sys/timex.h>
#include <sys/timerfd.h>
@@ -205,11 +204,8 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc)
return NULL;
sec = (time_t) (t / USEC_PER_SEC);
+ localtime_or_gmtime_r(&sec, &tm, utc);
- if (utc)
- gmtime_r(&sec, &tm);
- else
- localtime_r(&sec, &tm);
if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0)
return NULL;
@@ -235,10 +231,7 @@ static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool ut
return NULL;
sec = (time_t) (t / USEC_PER_SEC);
- if (utc)
- gmtime_r(&sec, &tm);
- else
- localtime_r(&sec, &tm);
+ localtime_or_gmtime_r(&sec, &tm, utc);
if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0)
return NULL;
@@ -484,9 +477,10 @@ int parse_timestamp(const char *t, usec_t *usec) {
};
const char *k;
+ bool utc;
struct tm tm, copy;
time_t x;
- usec_t plus = 0, minus = 0, ret;
+ usec_t x_usec, plus = 0, minus = 0, ret;
int r, weekday = -1;
unsigned i;
@@ -511,28 +505,15 @@ int parse_timestamp(const char *t, usec_t *usec) {
assert(t);
assert(usec);
- x = time(NULL);
- assert_se(localtime_r(&x, &tm));
- tm.tm_isdst = -1;
-
- if (streq(t, "now"))
- goto finish;
-
- else if (streq(t, "today")) {
- tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
- goto finish;
+ if (t[0] == '@')
+ return parse_sec(t + 1, usec);
- } else if (streq(t, "yesterday")) {
- tm.tm_mday --;
- tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
- goto finish;
+ ret = now(CLOCK_REALTIME);
- } else if (streq(t, "tomorrow")) {
- tm.tm_mday ++;
- tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ if (streq(t, "now"))
goto finish;
- } else if (t[0] == '+') {
+ else if (t[0] == '+') {
r = parse_sec(t+1, &plus);
if (r < 0)
return r;
@@ -546,35 +527,51 @@ int parse_timestamp(const char *t, usec_t *usec) {
goto finish;
- } else if (t[0] == '@')
- return parse_sec(t + 1, usec);
-
- else if (endswith(t, " ago")) {
- _cleanup_free_ char *z;
-
- z = strndup(t, strlen(t) - 4);
- if (!z)
- return -ENOMEM;
+ } else if (endswith(t, " ago")) {
+ t = strndupa(t, strlen(t) - strlen(" ago"));
- r = parse_sec(z, &minus);
+ r = parse_sec(t, &minus);
if (r < 0)
return r;
goto finish;
- } else if (endswith(t, " left")) {
- _cleanup_free_ char *z;
- z = strndup(t, strlen(t) - 4);
- if (!z)
- return -ENOMEM;
+ } else if (endswith(t, " left")) {
+ t = strndupa(t, strlen(t) - strlen(" left"));
- r = parse_sec(z, &plus);
+ r = parse_sec(t, &plus);
if (r < 0)
return r;
goto finish;
}
+ utc = endswith_no_case(t, " UTC");
+ if (utc)
+ t = strndupa(t, strlen(t) - strlen(" UTC"));
+
+ x = ret / USEC_PER_SEC;
+ x_usec = 0;
+
+ assert_se(localtime_or_gmtime_r(&x, &tm, utc));
+ tm.tm_isdst = -1;
+
+ if (streq(t, "today")) {
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto from_tm;
+
+ } else if (streq(t, "yesterday")) {
+ tm.tm_mday --;
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto from_tm;
+
+ } else if (streq(t, "tomorrow")) {
+ tm.tm_mday ++;
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto from_tm;
+ }
+
+
for (i = 0; i < ELEMENTSOF(day_nr); i++) {
size_t skip;
@@ -592,66 +589,106 @@ int parse_timestamp(const char *t, usec_t *usec) {
copy = tm;
k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
- if (k && *k == 0)
- goto finish;
+ if (k) {
+ if (*k == '.')
+ goto parse_usec;
+ else if (*k == 0)
+ goto from_tm;
+ }
tm = copy;
k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
- if (k && *k == 0)
- goto finish;
+ if (k) {
+ if (*k == '.')
+ goto parse_usec;
+ else if (*k == 0)
+ goto from_tm;
+ }
tm = copy;
k = strptime(t, "%y-%m-%d %H:%M", &tm);
if (k && *k == 0) {
tm.tm_sec = 0;
- goto finish;
+ goto from_tm;
}
tm = copy;
k = strptime(t, "%Y-%m-%d %H:%M", &tm);
if (k && *k == 0) {
tm.tm_sec = 0;
- goto finish;
+ goto from_tm;
}
tm = copy;
k = strptime(t, "%y-%m-%d", &tm);
if (k && *k == 0) {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
- goto finish;
+ goto from_tm;
}
tm = copy;
k = strptime(t, "%Y-%m-%d", &tm);
if (k && *k == 0) {
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
- goto finish;
+ goto from_tm;
}
tm = copy;
k = strptime(t, "%H:%M:%S", &tm);
- if (k && *k == 0)
- goto finish;
+ if (k) {
+ if (*k == '.')
+ goto parse_usec;
+ else if (*k == 0)
+ goto from_tm;
+ }
tm = copy;
k = strptime(t, "%H:%M", &tm);
if (k && *k == 0) {
tm.tm_sec = 0;
- goto finish;
+ goto from_tm;
}
return -EINVAL;
-finish:
- x = mktime(&tm);
+parse_usec:
+ {
+ char *end;
+ unsigned long long val;
+ size_t l;
+
+ k++;
+ if (*k < '0' || *k > '9')
+ return -EINVAL;
+
+ /* base 10 instead of base 0, .09 is not base 8 */
+ errno = 0;
+ val = strtoull(k, &end, 10);
+ if (*end || errno)
+ return -EINVAL;
+
+ l = end-k;
+
+ /* val has l digits, make them 6 */
+ for (; l < 6; l++)
+ val *= 10;
+ for (; l > 6; l--)
+ val /= 10;
+
+ x_usec = val;
+ }
+
+from_tm:
+ x = mktime_or_timegm(&tm, utc);
if (x == (time_t) -1)
return -EINVAL;
if (weekday >= 0 && tm.tm_wday != weekday)
return -EINVAL;
- ret = (usec_t) x * USEC_PER_SEC;
+ ret = (usec_t) x * USEC_PER_SEC + x_usec;
+finish:
ret += plus;
if (ret > minus)
ret -= minus;
@@ -1072,3 +1109,11 @@ int get_timezone(char **tz) {
*tz = z;
return 0;
}
+
+time_t mktime_or_timegm(struct tm *tm, bool utc) {
+ return utc ? timegm(tm) : mktime(tm);
+}
+
+struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) {
+ return utc ? gmtime_r(t, tm) : localtime_r(t, tm);
+}
diff --git a/src/basic/time-util.h b/src/basic/time-util.h
index de881e8fe1..417376ea96 100644
--- a/src/basic/time-util.h
+++ b/src/basic/time-util.h
@@ -21,8 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <inttypes.h>
+#include <stdio.h>
+#include <time.h>
typedef uint64_t usec_t;
typedef uint64_t nsec_t;
@@ -112,6 +113,11 @@ bool timezone_is_valid(const char *name);
clockid_t clock_boottime_or_monotonic(void);
-#define xstrftime(buf, fmt, tm) assert_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0)
+#define xstrftime(buf, fmt, tm) \
+ assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \
+ "xstrftime: " #buf "[] must be big enough")
int get_timezone(char **timezone);
+
+time_t mktime_or_timegm(struct tm *tm, bool utc);
+struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc);
diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c
index 8742ee757f..a8b6b6dace 100644
--- a/src/basic/unit-name.c
+++ b/src/basic/unit-name.c
@@ -839,6 +839,170 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState);
+static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
+ [UNIT_ACTIVE] = "active",
+ [UNIT_RELOADING] = "reloading",
+ [UNIT_INACTIVE] = "inactive",
+ [UNIT_FAILED] = "failed",
+ [UNIT_ACTIVATING] = "activating",
+ [UNIT_DEACTIVATING] = "deactivating"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
+
+static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
+ [AUTOMOUNT_DEAD] = "dead",
+ [AUTOMOUNT_WAITING] = "waiting",
+ [AUTOMOUNT_RUNNING] = "running",
+ [AUTOMOUNT_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
+
+static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
+ [BUSNAME_DEAD] = "dead",
+ [BUSNAME_MAKING] = "making",
+ [BUSNAME_REGISTERED] = "registered",
+ [BUSNAME_LISTENING] = "listening",
+ [BUSNAME_RUNNING] = "running",
+ [BUSNAME_SIGTERM] = "sigterm",
+ [BUSNAME_SIGKILL] = "sigkill",
+ [BUSNAME_FAILED] = "failed",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
+
+static const char* const device_state_table[_DEVICE_STATE_MAX] = {
+ [DEVICE_DEAD] = "dead",
+ [DEVICE_TENTATIVE] = "tentative",
+ [DEVICE_PLUGGED] = "plugged",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
+
+static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
+ [MOUNT_DEAD] = "dead",
+ [MOUNT_MOUNTING] = "mounting",
+ [MOUNT_MOUNTING_DONE] = "mounting-done",
+ [MOUNT_MOUNTED] = "mounted",
+ [MOUNT_REMOUNTING] = "remounting",
+ [MOUNT_UNMOUNTING] = "unmounting",
+ [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
+ [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
+ [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
+ [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
+ [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
+ [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
+ [MOUNT_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
+
+static const char* const path_state_table[_PATH_STATE_MAX] = {
+ [PATH_DEAD] = "dead",
+ [PATH_WAITING] = "waiting",
+ [PATH_RUNNING] = "running",
+ [PATH_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
+
+static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
+ [SCOPE_DEAD] = "dead",
+ [SCOPE_RUNNING] = "running",
+ [SCOPE_ABANDONED] = "abandoned",
+ [SCOPE_STOP_SIGTERM] = "stop-sigterm",
+ [SCOPE_STOP_SIGKILL] = "stop-sigkill",
+ [SCOPE_FAILED] = "failed",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
+
+static const char* const service_state_table[_SERVICE_STATE_MAX] = {
+ [SERVICE_DEAD] = "dead",
+ [SERVICE_START_PRE] = "start-pre",
+ [SERVICE_START] = "start",
+ [SERVICE_START_POST] = "start-post",
+ [SERVICE_RUNNING] = "running",
+ [SERVICE_EXITED] = "exited",
+ [SERVICE_RELOAD] = "reload",
+ [SERVICE_STOP] = "stop",
+ [SERVICE_STOP_SIGABRT] = "stop-sigabrt",
+ [SERVICE_STOP_SIGTERM] = "stop-sigterm",
+ [SERVICE_STOP_SIGKILL] = "stop-sigkill",
+ [SERVICE_STOP_POST] = "stop-post",
+ [SERVICE_FINAL_SIGTERM] = "final-sigterm",
+ [SERVICE_FINAL_SIGKILL] = "final-sigkill",
+ [SERVICE_FAILED] = "failed",
+ [SERVICE_AUTO_RESTART] = "auto-restart",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
+
+static const char* const slice_state_table[_SLICE_STATE_MAX] = {
+ [SLICE_DEAD] = "dead",
+ [SLICE_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
+
+static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
+ [SNAPSHOT_DEAD] = "dead",
+ [SNAPSHOT_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
+
+static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
+ [SOCKET_DEAD] = "dead",
+ [SOCKET_START_PRE] = "start-pre",
+ [SOCKET_START_CHOWN] = "start-chown",
+ [SOCKET_START_POST] = "start-post",
+ [SOCKET_LISTENING] = "listening",
+ [SOCKET_RUNNING] = "running",
+ [SOCKET_STOP_PRE] = "stop-pre",
+ [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
+ [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
+ [SOCKET_STOP_POST] = "stop-post",
+ [SOCKET_FINAL_SIGTERM] = "final-sigterm",
+ [SOCKET_FINAL_SIGKILL] = "final-sigkill",
+ [SOCKET_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
+
+static const char* const swap_state_table[_SWAP_STATE_MAX] = {
+ [SWAP_DEAD] = "dead",
+ [SWAP_ACTIVATING] = "activating",
+ [SWAP_ACTIVATING_DONE] = "activating-done",
+ [SWAP_ACTIVE] = "active",
+ [SWAP_DEACTIVATING] = "deactivating",
+ [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
+ [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
+ [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
+ [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
+ [SWAP_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
+
+static const char* const target_state_table[_TARGET_STATE_MAX] = {
+ [TARGET_DEAD] = "dead",
+ [TARGET_ACTIVE] = "active"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
+
+static const char* const timer_state_table[_TIMER_STATE_MAX] = {
+ [TIMER_DEAD] = "dead",
+ [TIMER_WAITING] = "waiting",
+ [TIMER_RUNNING] = "running",
+ [TIMER_ELAPSED] = "elapsed",
+ [TIMER_FAILED] = "failed"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
+
static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
[UNIT_REQUIRES] = "Requires",
[UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h
index 28b3a555f3..65b55d9554 100644
--- a/src/basic/unit-name.h
+++ b/src/basic/unit-name.h
@@ -27,11 +27,7 @@
#define UNIT_NAME_MAX 256
-typedef enum UnitType UnitType;
-typedef enum UnitLoadState UnitLoadState;
-typedef enum UnitDependency UnitDependency;
-
-enum UnitType {
+typedef enum UnitType {
UNIT_SERVICE = 0,
UNIT_SOCKET,
UNIT_BUSNAME,
@@ -47,9 +43,9 @@ enum UnitType {
UNIT_SCOPE,
_UNIT_TYPE_MAX,
_UNIT_TYPE_INVALID = -1
-};
+} UnitType;
-enum UnitLoadState {
+typedef enum UnitLoadState {
UNIT_STUB = 0,
UNIT_LOADED,
UNIT_NOT_FOUND,
@@ -58,9 +54,176 @@ enum UnitLoadState {
UNIT_MASKED,
_UNIT_LOAD_STATE_MAX,
_UNIT_LOAD_STATE_INVALID = -1
-};
-
-enum UnitDependency {
+} UnitLoadState;
+
+typedef enum UnitActiveState {
+ UNIT_ACTIVE,
+ UNIT_RELOADING,
+ UNIT_INACTIVE,
+ UNIT_FAILED,
+ UNIT_ACTIVATING,
+ UNIT_DEACTIVATING,
+ _UNIT_ACTIVE_STATE_MAX,
+ _UNIT_ACTIVE_STATE_INVALID = -1
+} UnitActiveState;
+
+typedef enum AutomountState {
+ AUTOMOUNT_DEAD,
+ AUTOMOUNT_WAITING,
+ AUTOMOUNT_RUNNING,
+ AUTOMOUNT_FAILED,
+ _AUTOMOUNT_STATE_MAX,
+ _AUTOMOUNT_STATE_INVALID = -1
+} AutomountState;
+
+typedef enum BusNameState {
+ BUSNAME_DEAD,
+ BUSNAME_MAKING,
+ BUSNAME_REGISTERED,
+ BUSNAME_LISTENING,
+ BUSNAME_RUNNING,
+ BUSNAME_SIGTERM,
+ BUSNAME_SIGKILL,
+ BUSNAME_FAILED,
+ _BUSNAME_STATE_MAX,
+ _BUSNAME_STATE_INVALID = -1
+} BusNameState;
+
+/* We simply watch devices, we cannot plug/unplug them. That
+ * simplifies the state engine greatly */
+typedef enum DeviceState {
+ DEVICE_DEAD,
+ DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */
+ DEVICE_PLUGGED, /* announced by udev */
+ _DEVICE_STATE_MAX,
+ _DEVICE_STATE_INVALID = -1
+} DeviceState;
+
+typedef enum MountState {
+ MOUNT_DEAD,
+ MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */
+ MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */
+ MOUNT_MOUNTED,
+ MOUNT_REMOUNTING,
+ MOUNT_UNMOUNTING,
+ MOUNT_MOUNTING_SIGTERM,
+ MOUNT_MOUNTING_SIGKILL,
+ MOUNT_REMOUNTING_SIGTERM,
+ MOUNT_REMOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING_SIGTERM,
+ MOUNT_UNMOUNTING_SIGKILL,
+ MOUNT_FAILED,
+ _MOUNT_STATE_MAX,
+ _MOUNT_STATE_INVALID = -1
+} MountState;
+
+typedef enum PathState {
+ PATH_DEAD,
+ PATH_WAITING,
+ PATH_RUNNING,
+ PATH_FAILED,
+ _PATH_STATE_MAX,
+ _PATH_STATE_INVALID = -1
+} PathState;
+
+typedef enum ScopeState {
+ SCOPE_DEAD,
+ SCOPE_RUNNING,
+ SCOPE_ABANDONED,
+ SCOPE_STOP_SIGTERM,
+ SCOPE_STOP_SIGKILL,
+ SCOPE_FAILED,
+ _SCOPE_STATE_MAX,
+ _SCOPE_STATE_INVALID = -1
+} ScopeState;
+
+typedef enum ServiceState {
+ SERVICE_DEAD,
+ SERVICE_START_PRE,
+ SERVICE_START,
+ SERVICE_START_POST,
+ SERVICE_RUNNING,
+ SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
+ SERVICE_RELOAD,
+ SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
+ SERVICE_STOP_SIGABRT, /* Watchdog timeout */
+ SERVICE_STOP_SIGTERM,
+ SERVICE_STOP_SIGKILL,
+ SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
+ SERVICE_FINAL_SIGKILL,
+ SERVICE_FAILED,
+ SERVICE_AUTO_RESTART,
+ _SERVICE_STATE_MAX,
+ _SERVICE_STATE_INVALID = -1
+} ServiceState;
+
+typedef enum SliceState {
+ SLICE_DEAD,
+ SLICE_ACTIVE,
+ _SLICE_STATE_MAX,
+ _SLICE_STATE_INVALID = -1
+} SliceState;
+
+typedef enum SnapshotState {
+ SNAPSHOT_DEAD,
+ SNAPSHOT_ACTIVE,
+ _SNAPSHOT_STATE_MAX,
+ _SNAPSHOT_STATE_INVALID = -1
+} SnapshotState;
+
+typedef enum SocketState {
+ SOCKET_DEAD,
+ SOCKET_START_PRE,
+ SOCKET_START_CHOWN,
+ SOCKET_START_POST,
+ SOCKET_LISTENING,
+ SOCKET_RUNNING,
+ SOCKET_STOP_PRE,
+ SOCKET_STOP_PRE_SIGTERM,
+ SOCKET_STOP_PRE_SIGKILL,
+ SOCKET_STOP_POST,
+ SOCKET_FINAL_SIGTERM,
+ SOCKET_FINAL_SIGKILL,
+ SOCKET_FAILED,
+ _SOCKET_STATE_MAX,
+ _SOCKET_STATE_INVALID = -1
+} SocketState;
+
+typedef enum SwapState {
+ SWAP_DEAD,
+ SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */
+ SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */
+ SWAP_ACTIVE,
+ SWAP_DEACTIVATING,
+ SWAP_ACTIVATING_SIGTERM,
+ SWAP_ACTIVATING_SIGKILL,
+ SWAP_DEACTIVATING_SIGTERM,
+ SWAP_DEACTIVATING_SIGKILL,
+ SWAP_FAILED,
+ _SWAP_STATE_MAX,
+ _SWAP_STATE_INVALID = -1
+} SwapState;
+
+
+typedef enum TargetState {
+ TARGET_DEAD,
+ TARGET_ACTIVE,
+ _TARGET_STATE_MAX,
+ _TARGET_STATE_INVALID = -1
+} TargetState;
+
+typedef enum TimerState {
+ TIMER_DEAD,
+ TIMER_WAITING,
+ TIMER_RUNNING,
+ TIMER_ELAPSED,
+ TIMER_FAILED,
+ _TIMER_STATE_MAX,
+ _TIMER_STATE_INVALID = -1
+} TimerState;
+
+typedef enum UnitDependency {
/* Positive dependencies */
UNIT_REQUIRES,
UNIT_REQUIRES_OVERRIDABLE,
@@ -107,7 +270,7 @@ enum UnitDependency {
_UNIT_DEPENDENCY_MAX,
_UNIT_DEPENDENCY_INVALID = -1
-};
+} UnitDependency;
typedef enum UnitNameFlags {
UNIT_NAME_PLAIN = 1, /* Allow foo.service */
@@ -176,5 +339,47 @@ UnitType unit_type_from_string(const char *s) _pure_;
const char *unit_load_state_to_string(UnitLoadState i) _const_;
UnitLoadState unit_load_state_from_string(const char *s) _pure_;
+const char *unit_active_state_to_string(UnitActiveState i) _const_;
+UnitActiveState unit_active_state_from_string(const char *s) _pure_;
+
+const char* automount_state_to_string(AutomountState i) _const_;
+AutomountState automount_state_from_string(const char *s) _pure_;
+
+const char* busname_state_to_string(BusNameState i) _const_;
+BusNameState busname_state_from_string(const char *s) _pure_;
+
+const char* device_state_to_string(DeviceState i) _const_;
+DeviceState device_state_from_string(const char *s) _pure_;
+
+const char* mount_state_to_string(MountState i) _const_;
+MountState mount_state_from_string(const char *s) _pure_;
+
+const char* path_state_to_string(PathState i) _const_;
+PathState path_state_from_string(const char *s) _pure_;
+
+const char* scope_state_to_string(ScopeState i) _const_;
+ScopeState scope_state_from_string(const char *s) _pure_;
+
+const char* service_state_to_string(ServiceState i) _const_;
+ServiceState service_state_from_string(const char *s) _pure_;
+
+const char* slice_state_to_string(SliceState i) _const_;
+SliceState slice_state_from_string(const char *s) _pure_;
+
+const char* snapshot_state_to_string(SnapshotState i) _const_;
+SnapshotState snapshot_state_from_string(const char *s) _pure_;
+
+const char* socket_state_to_string(SocketState i) _const_;
+SocketState socket_state_from_string(const char *s) _pure_;
+
+const char* swap_state_to_string(SwapState i) _const_;
+SwapState swap_state_from_string(const char *s) _pure_;
+
+const char* target_state_to_string(TargetState i) _const_;
+TargetState target_state_from_string(const char *s) _pure_;
+
+const char *timer_state_to_string(TimerState i) _const_;
+TimerState timer_state_from_string(const char *s) _pure_;
+
const char *unit_dependency_to_string(UnitDependency i) _const_;
UnitDependency unit_dependency_from_string(const char *s) _pure_;
diff --git a/src/basic/util.c b/src/basic/util.c
index e3b2af8e02..8b896a2df3 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -19,49 +19,48 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <unistd.h>
+#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
-#include <stdlib.h>
-#include <signal.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <grp.h>
+#include <langinfo.h>
#include <libintl.h>
-#include <stdio.h>
-#include <syslog.h>
-#include <sched.h>
-#include <sys/resource.h>
+#include <limits.h>
+#include <linux/magic.h>
#include <linux/sched.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/ioctl.h>
-#include <stdarg.h>
+#include <locale.h>
+#include <netinet/ip.h>
#include <poll.h>
-#include <ctype.h>
-#include <sys/prctl.h>
-#include <sys/utsname.h>
#include <pwd.h>
-#include <netinet/ip.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <glob.h>
-#include <grp.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
#include <sys/mman.h>
-#include <sys/vfs.h>
#include <sys/mount.h>
-#include <linux/magic.h>
-#include <limits.h>
-#include <langinfo.h>
-#include <locale.h>
#include <sys/personality.h>
-#include <sys/xattr.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
#include <sys/statvfs.h>
-#include <sys/file.h>
-#include <linux/fs.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+#include <sys/wait.h>
+#include <sys/xattr.h>
+#include <syslog.h>
+#include <unistd.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(). */
+ * 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
@@ -69,31 +68,35 @@
#include <sys/auxv.h>
#endif
-#include "config.h"
-#include "macro.h"
-#include "util.h"
+/* We include linux/fs.h as last of the system headers, as it
+ * otherwise conflicts with sys/mount.h. Yay, Linux is great! */
+#include <linux/fs.h>
+
+#include "build.h"
+#include "def.h"
+#include "device-nodes.h"
+#include "env-util.h"
+#include "exit-status.h"
+#include "fileio.h"
+#include "formats-util.h"
+#include "gunicode.h"
+#include "hashmap.h"
+#include "hostname-util.h"
#include "ioprio.h"
-#include "missing.h"
#include "log.h"
-#include "strv.h"
+#include "macro.h"
+#include "missing.h"
#include "mkdir.h"
#include "path-util.h"
-#include "exit-status.h"
-#include "hashmap.h"
-#include "env-util.h"
-#include "fileio.h"
-#include "device-nodes.h"
-#include "utf8.h"
-#include "gunicode.h"
-#include "virt.h"
-#include "def.h"
-#include "sparse-endian.h"
-#include "formats-util.h"
#include "process-util.h"
#include "random-util.h"
-#include "terminal-util.h"
-#include "hostname-util.h"
#include "signal-util.h"
+#include "sparse-endian.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "utf8.h"
+#include "util.h"
+#include "virt.h"
/* Put this test here for a lack of better place */
assert_cc(EAGAIN == EWOULDBLOCK);
@@ -354,6 +357,17 @@ FILE* safe_fclose(FILE *f) {
return NULL;
}
+DIR* safe_closedir(DIR *d) {
+
+ if (d) {
+ PROTECT_ERRNO;
+
+ assert_se(closedir(d) >= 0 || errno != EBADF);
+ }
+
+ return NULL;
+}
+
int unlink_noerrno(const char *path) {
PROTECT_ERRNO;
int r;
@@ -2133,7 +2147,13 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
assert(fd >= 0);
assert(buf);
- while (nbytes > 0) {
+ /* If called with nbytes == 0, let's call read() at least
+ * once, to validate the operation */
+
+ if (nbytes > (size_t) SSIZE_MAX)
+ return -EINVAL;
+
+ do {
ssize_t k;
k = read(fd, p, nbytes);
@@ -2147,7 +2167,7 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
* and expect that any error/EOF is reported
* via read() */
- fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
+ (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
continue;
}
@@ -2157,10 +2177,12 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
if (k == 0)
return n;
+ assert((size_t) k <= nbytes);
+
p += k;
nbytes -= k;
n += k;
- }
+ } while (nbytes > 0);
return n;
}
@@ -2170,9 +2192,10 @@ int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
n = loop_read(fd, buf, nbytes, do_poll);
if (n < 0)
- return n;
+ return (int) n;
if ((size_t) n != nbytes)
return -EIO;
+
return 0;
}
@@ -2182,7 +2205,8 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
assert(fd >= 0);
assert(buf);
- errno = 0;
+ if (nbytes > (size_t) SSIZE_MAX)
+ return -EINVAL;
do {
ssize_t k;
@@ -2197,16 +2221,18 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
* and expect that any error/EOF is reported
* via write() */
- fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
+ (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
continue;
}
return -errno;
}
- if (nbytes > 0 && k == 0) /* Can't really happen */
+ if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
return -EIO;
+ assert((size_t) k <= nbytes);
+
p += k;
nbytes -= k;
} while (nbytes > 0);
@@ -2525,34 +2551,6 @@ int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
return 0;
}
-cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
- cpu_set_t *r;
- unsigned n = 1024;
-
- /* Allocates the cpuset in the right size */
-
- for (;;) {
- if (!(r = CPU_ALLOC(n)))
- return NULL;
-
- if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) {
- CPU_ZERO_S(CPU_ALLOC_SIZE(n), r);
-
- if (ncpus)
- *ncpus = n;
-
- return r;
- }
-
- CPU_FREE(r);
-
- if (errno != EINVAL)
- return NULL;
-
- n *= 2;
- }
-}
-
int files_same(const char *filea, const char *fileb) {
struct stat a, b;
@@ -3701,6 +3699,10 @@ static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
+bool log_facility_unshifted_is_valid(int facility) {
+ return facility >= 0 && facility <= LOG_FAC(~0);
+}
+
static const char *const log_level_table[] = {
[LOG_EMERG] = "emerg",
[LOG_ALERT] = "alert",
@@ -3714,6 +3716,10 @@ static const char *const log_level_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
+bool log_level_is_valid(int level) {
+ return level >= 0 && level <= LOG_DEBUG;
+}
+
static const char* const sched_policy_table[] = {
[SCHED_OTHER] = "other",
[SCHED_BATCH] = "batch",
@@ -5236,6 +5242,19 @@ unsigned long personality_from_string(const char *p) {
if (streq(p, "x86"))
return PER_LINUX;
+
+#elif defined(__s390x__)
+
+ if (streq(p, "s390"))
+ return PER_LINUX32;
+
+ if (streq(p, "s390x"))
+ return PER_LINUX;
+
+#elif defined(__s390__)
+
+ if (streq(p, "s390"))
+ return PER_LINUX;
#endif
return PERSONALITY_INVALID;
@@ -5255,6 +5274,20 @@ const char* personality_to_string(unsigned long p) {
if (p == PER_LINUX)
return "x86";
+
+#elif defined(__s390x__)
+
+ if (p == PER_LINUX)
+ return "s390x";
+
+ if (p == PER_LINUX32)
+ return "s390";
+
+#elif defined(__s390__)
+
+ if (p == PER_LINUX)
+ return "s390";
+
#endif
return NULL;
@@ -5319,15 +5352,13 @@ int update_reboot_param_file(const char *param) {
int r = 0;
if (param) {
-
r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
if (r < 0)
- log_error("Failed to write reboot param to "
- REBOOT_PARAM_FILE": %s", strerror(-r));
+ return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
} else
- unlink(REBOOT_PARAM_FILE);
+ (void) unlink(REBOOT_PARAM_FILE);
- return r;
+ return 0;
}
int umount_recursive(const char *prefix, int flags) {
@@ -5961,6 +5992,7 @@ int extract_first_word_and_warn(
const char *filename,
unsigned line,
const char *rvalue) {
+
/* Try to unquote it, if it fails, warn about it and try again but this
* time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
* in invalid escape sequences. */
@@ -5969,17 +6001,17 @@ int extract_first_word_and_warn(
save = *p;
r = extract_first_word(p, ret, separators, flags);
- if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) {
+ if (r < 0 && !(flags & EXTRACT_CUNESCAPE_RELAX)) {
+
/* Retry it with EXTRACT_CUNESCAPE_RELAX. */
*p = save;
r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
else
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Invalid escape sequences in command line: \"%s\"", rvalue);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue);
}
+
return r;
}
@@ -6063,133 +6095,20 @@ int free_and_strdup(char **p, const char *s) {
return 1;
}
-int ptsname_malloc(int fd, char **ret) {
- size_t l = 100;
-
- assert(fd >= 0);
- assert(ret);
-
- for (;;) {
- char *c;
-
- c = new(char, l);
- if (!c)
- return -ENOMEM;
-
- if (ptsname_r(fd, c, l) == 0) {
- *ret = c;
- return 0;
- }
- if (errno != ERANGE) {
- free(c);
- return -errno;
- }
-
- free(c);
- l *= 2;
- }
-}
-
-int openpt_in_namespace(pid_t pid, int flags) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
- _cleanup_close_pair_ int pair[2] = { -1, -1 };
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- siginfo_t si;
- pid_t child;
- int r;
-
- assert(pid > 0);
-
- r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
- if (r < 0)
- return r;
-
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
- return -errno;
-
- child = fork();
- if (child < 0)
- return -errno;
-
- if (child == 0) {
- int master;
-
- pair[0] = safe_close(pair[0]);
-
- r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
- if (r < 0)
- _exit(EXIT_FAILURE);
-
- master = posix_openpt(flags);
- if (master < 0)
- _exit(EXIT_FAILURE);
-
- if (unlockpt(master) < 0)
- _exit(EXIT_FAILURE);
-
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
- if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
- _exit(EXIT_FAILURE);
-
- _exit(EXIT_SUCCESS);
- }
-
- pair[1] = safe_close(pair[1]);
-
- r = wait_for_terminate(child, &si);
- if (r < 0)
- return r;
- if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return -EIO;
-
- if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
- return -errno;
-
- CMSG_FOREACH(cmsg, &mh)
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- int *fds;
- unsigned n_fds;
-
- fds = (int*) CMSG_DATA(cmsg);
- n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-
- if (n_fds != 1) {
- close_many(fds, n_fds);
- return -EIO;
- }
-
- return fds[0];
- }
-
- return -EIO;
-}
-
ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) {
+ char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
_cleanup_close_ int fd = -1;
ssize_t l;
/* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */
- fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOATIME|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
+ fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
return -errno;
- l = fgetxattr(fd, attribute, value, size);
+ xsprintf(fn, "/proc/self/fd/%i", fd);
+
+ l = getxattr(fn, attribute, value, size);
if (l < 0)
return -errno;
@@ -6538,7 +6457,7 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
for (i = 0; i < len; ++i)
if (streq_ptr(table[i], key))
- return (ssize_t)i;
+ return (ssize_t) i;
return -1;
}
@@ -6775,3 +6694,109 @@ int fgetxattr_malloc(int fd, const char *name, char **value) {
return -errno;
}
}
+
+int send_one_fd(int transport_fd, int fd, int flags) {
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } control = {};
+ struct msghdr mh = {
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg;
+
+ assert(transport_fd >= 0);
+ assert(fd >= 0);
+
+ cmsg = CMSG_FIRSTHDR(&mh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+
+ mh.msg_controllen = CMSG_SPACE(sizeof(int));
+ if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int receive_one_fd(int transport_fd, int flags) {
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(int))];
+ } control = {};
+ struct msghdr mh = {
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+ struct cmsghdr *cmsg, *found = NULL;
+
+ assert(transport_fd >= 0);
+
+ /*
+ * Receive a single FD via @transport_fd. We don't care for
+ * the transport-type. We retrieve a single FD at most, so for
+ * packet-based transports, the caller must ensure to send
+ * only a single FD per packet. This is best used in
+ * combination with send_one_fd().
+ */
+
+ if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0)
+ return -errno;
+
+ CMSG_FOREACH(cmsg, &mh) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+ assert(!found);
+ found = cmsg;
+ break;
+ }
+ }
+
+ if (!found) {
+ cmsg_close_all(&mh);
+ return -EIO;
+ }
+
+ return *(int*) CMSG_DATA(found);
+}
+
+void nop_signal_handler(int sig) {
+ /* nothing here */
+}
+
+int version(void) {
+ puts(PACKAGE_STRING "\n"
+ SYSTEMD_FEATURES);
+ return 0;
+}
+
+bool fdname_is_valid(const char *s) {
+ const char *p;
+
+ /* Validates a name for $LISTEN_FDNAMES. We basically allow
+ * everything ASCII that's not a control character. Also, as
+ * special exception the ":" character is not allowed, as we
+ * use that as field separator in $LISTEN_FDNAMES.
+ *
+ * Note that the empty string is explicitly allowed
+ * here. However, we limit the length of the names to 255
+ * characters. */
+
+ if (!s)
+ return false;
+
+ for (p = s; *p; p++) {
+ if (*p < ' ')
+ return false;
+ if (*p >= 127)
+ return false;
+ if (*p == ':')
+ return false;
+ }
+
+ return p - s < 256;
+}
diff --git a/src/basic/util.h b/src/basic/util.h
index c7dff9a86d..2544ad0830 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -22,30 +22,29 @@
***/
#include <alloca.h>
+#include <dirent.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <time.h>
+#include <limits.h>
+#include <locale.h>
+#include <mntent.h>
#include <stdarg.h>
#include <stdbool.h>
-#include <stdlib.h>
+#include <stddef.h>
#include <stdio.h>
-#include <sched.h>
-#include <limits.h>
-#include <sys/types.h>
+#include <stdlib.h>
+#include <sys/inotify.h>
#include <sys/socket.h>
#include <sys/stat.h>
-#include <dirent.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <locale.h>
-#include <mntent.h>
-#include <sys/inotify.h>
#include <sys/statfs.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include "formats-util.h"
#include "macro.h"
#include "missing.h"
#include "time-util.h"
-#include "formats-util.h"
/* What is interpreted as whitespace? */
#define WHITESPACE " \t\n\r"
@@ -151,6 +150,7 @@ void close_many(const int fds[], unsigned n_fd);
int fclose_nointr(FILE *f);
FILE* safe_fclose(FILE *f);
+DIR* safe_closedir(DIR *f);
int parse_size(const char *t, uint64_t base, uint64_t *size);
@@ -160,7 +160,10 @@ int parse_uid(const char *s, uid_t* ret_uid);
#define parse_gid(s, ret_gid) parse_uid(s, ret_gid)
bool uid_is_valid(uid_t uid);
-#define gid_is_valid(gid) uid_is_valid(gid)
+
+static inline bool gid_is_valid(gid_t gid) {
+ return uid_is_valid((uid_t) gid);
+}
int safe_atou(const char *s, unsigned *ret_u);
int safe_atoi(const char *s, int *ret_i);
@@ -289,9 +292,9 @@ bool chars_intersect(const char *a, const char *b) _pure_;
ssize_t string_table_lookup(const char * const *table, size_t len, const char *key);
-#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
- scope inline type name##_from_string(const char *s) { \
- return (type)string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
+#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
+ scope type name##_from_string(const char *s) { \
+ return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
}
#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
@@ -308,17 +311,15 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
int name##_to_string_alloc(type i, char **str) { \
char *s; \
- int r; \
if (i < 0 || i > max) \
return -ERANGE; \
if (i < (type) ELEMENTSOF(name##_table)) { \
s = strdup(name##_table[i]); \
if (!s) \
- return log_oom(); \
+ return -ENOMEM; \
} else { \
- r = asprintf(&s, "%i", i); \
- if (r < 0) \
- return log_oom(); \
+ if (asprintf(&s, "%i", i) < 0) \
+ return -ENOMEM; \
} \
*str = s; \
return 0; \
@@ -326,10 +327,10 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
type name##_from_string(const char *s) { \
type i; \
unsigned u = 0; \
- assert(s); \
- for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \
- if (name##_table[i] && \
- streq(name##_table[i], s)) \
+ if (!s) \
+ return (type) -1; \
+ for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \
+ if (streq_ptr(name##_table[i], s)) \
return i; \
if (safe_atou(s, &u) >= 0 && u <= max) \
return (type) u; \
@@ -369,12 +370,9 @@ int fd_is_temporary_fs(int fd);
int pipe_eof(int fd);
-DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE);
-#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp)
-
-cpu_set_t* cpu_set_malloc(unsigned *ncpus);
-
-#define xsprintf(buf, fmt, ...) assert_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf))
+#define xsprintf(buf, fmt, ...) \
+ assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \
+ "xsprintf: " #buf "[] must be big enough")
int files_same(const char *filea, const char *fileb);
@@ -458,9 +456,11 @@ int sigchld_code_from_string(const char *s) _pure_;
int log_facility_unshifted_to_string_alloc(int i, char **s);
int log_facility_unshifted_from_string(const char *s);
+bool log_facility_unshifted_is_valid(int faciliy);
int log_level_to_string_alloc(int i, char **s);
int log_level_from_string(const char *s);
+bool log_level_is_valid(int level);
int sched_policy_to_string_alloc(int i, char **s);
int sched_policy_from_string(const char *s);
@@ -893,10 +893,6 @@ union inotify_event_buffer {
#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW)
-int ptsname_malloc(int fd, char **ret);
-
-int openpt_in_namespace(pid_t pid, int flags);
-
ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags);
int fd_setcrtime(int fd, usec_t usec);
@@ -936,3 +932,12 @@ int reset_uid_gid(void);
int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
int fgetxattr_malloc(int fd, const char *name, char **value);
+
+int send_one_fd(int transport_fd, int fd, int flags);
+int receive_one_fd(int transport_fd, int flags);
+
+void nop_signal_handler(int sig);
+
+int version(void);
+
+bool fdname_is_valid(const char *s);
diff --git a/src/basic/virt.c b/src/basic/virt.c
index 1fc6c1baba..70543177b6 100644
--- a/src/basic/virt.c
+++ b/src/basic/virt.c
@@ -240,7 +240,7 @@ static int detect_vm_zvm(void) {
_cleanup_free_ char *t = NULL;
int r;
- r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t);
+ r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t);
if (r == -ENOENT)
return VIRTUALIZATION_NONE;
if (r < 0)
diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c
index 1e216f52bd..ddb5c88806 100644
--- a/src/binfmt/binfmt.c
+++ b/src/binfmt/binfmt.c
@@ -19,20 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "conf-files.h"
+#include "fileio.h"
#include "log.h"
#include "strv.h"
#include "util.h"
-#include "conf-files.h"
-#include "fileio.h"
-#include "build.h"
static const char conf_file_dirs[] = CONF_DIRS_NULSTR("binfmt");
@@ -143,9 +142,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case '?':
return -EINVAL;
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index ac1711b318..f991e30cfa 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -20,28 +20,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <getopt.h>
-#include <stdlib.h>
#include <assert.h>
-#include <sys/statfs.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <dirent.h>
+#include <blkid/blkid.h>
#include <ctype.h>
-#include <limits.h>
+#include <dirent.h>
+#include <errno.h>
#include <ftw.h>
+#include <getopt.h>
+#include <limits.h>
#include <stdbool.h>
-#include <blkid/blkid.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <unistd.h>
+#include "blkid-util.h"
#include "efivars.h"
-#include "build.h"
-#include "util.h"
#include "rm-rf.h"
-#include "blkid-util.h"
+#include "util.h"
static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) {
struct statfs sfs;
@@ -967,8 +966,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- printf(VERSION "\n");
- return 0;
+ return version();
case ARG_PATH:
arg_path = optarg;
diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c
index c66f12e3a6..db5fc863b0 100644
--- a/src/bootchart/svg.c
+++ b/src/bootchart/svg.c
@@ -30,6 +30,7 @@
#include <sys/utsname.h>
#include <fcntl.h>
+#include "architecture.h"
#include "util.h"
#include "fileio.h"
#include "macro.h"
@@ -147,7 +148,7 @@ static int svg_title(FILE *of, const char *build, int pscount, double log_start,
_cleanup_free_ char *model = NULL;
_cleanup_free_ char *buf = NULL;
char date[256] = "Unknown";
- char *cpu;
+ const char *cpu;
char *c;
time_t t;
int r;
@@ -188,20 +189,11 @@ static int svg_title(FILE *of, const char *build, int pscount, double log_start,
assert_se(r > 0);
/* CPU type */
- r = read_full_file("/proc/cpuinfo", &buf, NULL);
+ r = get_proc_field("/proc/cpuinfo", PROC_CPUINFO_MODEL, "\n", &buf);
if (r < 0)
- return log_error_errno(r, "Unable to read cpuinfo: %m");
-
- cpu = strstr(buf, "model name");
- if (!cpu) {
- log_error("Unable to read module name from cpuinfo.\n");
- return -ENOENT;
- }
-
- cpu += 13;
- c = strchr(cpu, '\n');
- if (c)
- *c = '\0';
+ cpu = "Unknown";
+ else
+ cpu = buf;
fprintf(of, "<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
uts.nodename, date);
diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index 3cc3b33ae7..2bc265d9b4 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -22,26 +22,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
-#include <sys/prctl.h>
-#include <stddef.h>
#include <getopt.h>
#include <pthread.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <unistd.h>
-#include "log.h"
-#include "util.h"
#include "sd-daemon.h"
+
#include "bus-internal.h"
-#include "build.h"
-#include "strv.h"
-#include "def.h"
-#include "capability.h"
#include "bus-xml-policy.h"
-#include "proxy.h"
+#include "capability.h"
+#include "def.h"
#include "formats-util.h"
+#include "log.h"
+#include "proxy.h"
+#include "strv.h"
+#include "util.h"
static char *arg_address = NULL;
static char **arg_configuration = NULL;
@@ -215,9 +215,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ADDRESS:
r = free_and_strdup(&arg_address, optarg);
diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c
index f275f6705f..168fc9ead0 100644
--- a/src/bus-proxyd/stdio-bridge.c
+++ b/src/bus-proxyd/stdio-bridge.c
@@ -21,23 +21,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <string.h>
#include <errno.h>
-#include <stddef.h>
#include <getopt.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
-#include "log.h"
-#include "util.h"
#include "sd-daemon.h"
#include "sd-bus.h"
+
#include "bus-internal.h"
#include "bus-util.h"
-#include "build.h"
-#include "strv.h"
#include "def.h"
-#include "proxy.h"
#include "formats-util.h"
+#include "log.h"
+#include "proxy.h"
+#include "strv.h"
+#include "util.h"
static char *arg_address = NULL;
static char *arg_command_line_buffer = NULL;
@@ -86,9 +86,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ADDRESS: {
char *a;
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index 4fb642e7b3..41c539a1bc 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -19,25 +19,25 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <unistd.h>
#include <errno.h>
#include <getopt.h>
+#include <stdio.h>
#include <string.h>
+#include <unistd.h>
+
+#include "sd-bus.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
+#include "fileio.h"
#include "log.h"
-#include "path-util.h"
-#include "util.h"
-#include "pager.h"
-#include "build.h"
#include "output-mode.h"
-#include "fileio.h"
-#include "sd-bus.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "pager.h"
+#include "path-util.h"
#include "unit-name.h"
+#include "util.h"
static bool arg_no_pager = false;
static bool arg_kernel_threads = false;
@@ -89,9 +89,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
@@ -147,7 +145,7 @@ static int get_cgroup_root(char **ret) {
if (!path)
return log_oom();
- r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
+ r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
if (r < 0)
return log_error_errno(r, "Failed to create bus connection: %m");
@@ -165,6 +163,13 @@ static int get_cgroup_root(char **ret) {
return 0;
}
+static void show_cg_info(const char *controller, const char *path) {
+ if (cg_unified() <= 0)
+ printf("Controller %s; ", controller);
+ printf("Control group %s:\n", isempty(path) ? "/" : path);
+ fflush(stdout);
+}
+
int main(int argc, char *argv[]) {
int r, output_flags;
@@ -225,11 +230,7 @@ int main(int argc, char *argv[]) {
} else
path = root;
- if (cg_unified() > 0)
- printf("Control group %s:\n", path);
- else
- printf("Controller %s; control group %s:\n", controller, path);
- fflush(stdout);
+ show_cg_info(controller, path);
q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags);
}
@@ -266,8 +267,7 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
- printf("Control group %s:\n", isempty(root) ? "/" : root);
- fflush(stdout);
+ show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root);
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags);
}
diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c
index 612bc8fdec..b79519dd09 100644
--- a/src/cgroups-agent/cgroups-agent.c
+++ b/src/cgroups-agent/cgroups-agent.c
@@ -43,7 +43,7 @@ int main(int argc, char *argv[]) {
* this to avoid an activation loop when we start dbus when we
* are called when the dbus service is shut down. */
- r = bus_open_system_systemd(&bus);
+ r = bus_connect_system_systemd(&bus);
if (r < 0) {
/* If we couldn't connect we assume this was triggered
* while systemd got restarted/transitioned from
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index f26aeb39df..ad9cd2532f 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -19,23 +19,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
#include <alloca.h>
+#include <errno.h>
#include <getopt.h>
#include <signal.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sd-bus.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "fileio.h"
+#include "hashmap.h"
#include "path-util.h"
-#include "terminal-util.h"
#include "process-util.h"
+#include "terminal-util.h"
+#include "unit-name.h"
#include "util.h"
-#include "hashmap.h"
-#include "cgroup-util.h"
-#include "build.h"
-#include "fileio.h"
typedef struct Group {
char *path;
@@ -45,7 +49,7 @@ typedef struct Group {
bool memory_valid:1;
bool io_valid:1;
- unsigned n_tasks;
+ uint64_t n_tasks;
unsigned cpu_iteration;
nsec_t cpu_usage;
@@ -65,7 +69,13 @@ static unsigned arg_iterations = (unsigned) -1;
static bool arg_batch = false;
static bool arg_raw = false;
static usec_t arg_delay = 1*USEC_PER_SEC;
-static bool arg_kernel_threads = false;
+static char* arg_machine = NULL;
+
+enum {
+ COUNT_PIDS,
+ COUNT_USERSPACE_PROCESSES,
+ COUNT_ALL_PROCESSES,
+} arg_count = COUNT_PIDS;
static bool arg_recursive = true;
static enum {
@@ -73,7 +83,7 @@ static enum {
ORDER_TASKS,
ORDER_CPU,
ORDER_MEMORY,
- ORDER_IO
+ ORDER_IO,
} arg_order = ORDER_CPU;
static enum {
@@ -153,7 +163,7 @@ static int process(
}
}
- if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
+ if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES)) {
_cleanup_fclose_ FILE *f = NULL;
pid_t pid;
@@ -166,7 +176,7 @@ static int process(
g->n_tasks = 0;
while (cg_read_pid(f, &pid) > 0) {
- if (!arg_kernel_threads && is_kernel_thread(pid) > 0)
+ if (arg_count == COUNT_USERSPACE_PROCESSES && is_kernel_thread(pid) > 0)
continue;
g->n_tasks++;
@@ -175,6 +185,26 @@ static int process(
if (g->n_tasks > 0)
g->n_tasks_valid = true;
+ } else if (streq(controller, "pids") && arg_count == COUNT_PIDS) {
+ _cleanup_free_ char *p = NULL, *v = NULL;
+
+ r = cg_get_path(controller, path, "pids.current", &p);
+ if (r < 0)
+ return r;
+
+ r = read_one_line_file(p, &v);
+ if (r == -ENOENT)
+ return 0;
+ if (r < 0)
+ return r;
+
+ r = safe_atou64(v, &g->n_tasks);
+ if (r < 0)
+ return r;
+
+ if (g->n_tasks > 0)
+ g->n_tasks_valid = true;
+
} else if (streq(controller, "cpuacct") && cg_unified() <= 0) {
_cleanup_free_ char *p = NULL, *v = NULL;
uint64_t new_usage;
@@ -371,6 +401,7 @@ static int refresh_one(
return r;
if (arg_recursive &&
+ IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES) &&
child &&
child->n_tasks_valid &&
streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
@@ -409,6 +440,9 @@ static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration)
r = refresh_one("blkio", root, a, b, iteration, 0, NULL);
if (r < 0)
return r;
+ r = refresh_one("pids", root, a, b, iteration, 0, NULL);
+ if (r < 0)
+ return r;
return 0;
}
@@ -494,9 +528,6 @@ static int group_compare(const void*a, const void *b) {
return path_compare(x->path, y->path);
}
-#define ON ANSI_HIGHLIGHT_ON
-#define OFF ANSI_HIGHLIGHT_OFF
-
static void display(Hashmap *a) {
Iterator i;
Group *g;
@@ -507,10 +538,8 @@ static void display(Hashmap *a) {
assert(a);
- /* Set cursor to top left corner and clear screen */
if (on_tty())
- fputs("\033[H"
- "\033[2J", stdout);
+ fputs(ANSI_HOME_CLEAR, stdout);
array = alloca(sizeof(Group*) * hashmap_size(a));
@@ -542,23 +571,30 @@ static void display(Hashmap *a) {
rows = 10;
if (on_tty()) {
+ const char *on, *off;
+
path_columns = columns() - 36 - strlen(buffer);
if (path_columns < 10)
path_columns = 10;
- printf("%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s\n\n",
- arg_order == ORDER_PATH ? ON : "", path_columns, "Control Group",
- arg_order == ORDER_PATH ? OFF : "",
- arg_order == ORDER_TASKS ? ON : "", "Tasks",
- arg_order == ORDER_TASKS ? OFF : "",
- arg_order == ORDER_CPU ? ON : "", buffer,
- arg_order == ORDER_CPU ? OFF : "",
- arg_order == ORDER_MEMORY ? ON : "", "Memory",
- arg_order == ORDER_MEMORY ? OFF : "",
- arg_order == ORDER_IO ? ON : "", "Input/s",
- arg_order == ORDER_IO ? OFF : "",
- arg_order == ORDER_IO ? ON : "", "Output/s",
- arg_order == ORDER_IO ? OFF : "");
+ on = ansi_highlight_underline();
+ off = ansi_underline();
+
+ printf("%s%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s%s\n",
+ ansi_underline(),
+ arg_order == ORDER_PATH ? on : "", path_columns, "Control Group",
+ arg_order == ORDER_PATH ? off : "",
+ arg_order == ORDER_TASKS ? on : "", arg_count == COUNT_PIDS ? "Tasks" : arg_count == COUNT_USERSPACE_PROCESSES ? "Procs" : "Proc+",
+ arg_order == ORDER_TASKS ? off : "",
+ arg_order == ORDER_CPU ? on : "", buffer,
+ arg_order == ORDER_CPU ? off : "",
+ arg_order == ORDER_MEMORY ? on : "", "Memory",
+ arg_order == ORDER_MEMORY ? off : "",
+ arg_order == ORDER_IO ? on : "", "Input/s",
+ arg_order == ORDER_IO ? off : "",
+ arg_order == ORDER_IO ? on : "", "Output/s",
+ arg_order == ORDER_IO ? off : "",
+ ansi_normal());
} else
path_columns = maxtpath;
@@ -566,7 +602,7 @@ static void display(Hashmap *a) {
_cleanup_free_ char *ellipsized = NULL;
const char *path;
- if (on_tty() && j + 5 > rows)
+ if (on_tty() && j + 6 > rows)
break;
g = array[j];
@@ -576,7 +612,7 @@ static void display(Hashmap *a) {
printf("%-*s", path_columns, ellipsized ?: path);
if (g->n_tasks_valid)
- printf(" %7u", g->n_tasks);
+ printf(" %7" PRIu64, g->n_tasks);
else
fputs(" -", stdout);
@@ -602,19 +638,21 @@ static void help(void) {
" -h --help Show this help\n"
" --version Show package version\n"
" -p --order=path Order by path\n"
- " -t --order=tasks Order by number of tasks\n"
+ " -t --order=tasks Order by number of tasks/processes\n"
" -c --order=cpu Order by CPU load (default)\n"
" -m --order=memory Order by memory load\n"
" -i --order=io Order by IO load\n"
" -r --raw Provide raw (not human-readable) numbers\n"
" --cpu=percentage Show CPU usage as percentage (default)\n"
" --cpu=time Show CPU usage as time\n"
- " -k Include kernel threads in task count\n"
- " --recursive=BOOL Sum up task count recursively\n"
+ " -P Count userspace processes instead of tasks (excl. kernel)\n"
+ " -k Count all processes instead of tasks (incl. kernel)\n"
+ " --recursive=BOOL Sum up process count recursively\n"
" -d --delay=DELAY Delay between updates\n"
" -n --iterations=N Run for N iterations before exiting\n"
" -b --batch Run in batch mode, accepting no input\n"
" --depth=DEPTH Maximum traversal depth (default: %u)\n"
+ " -M --machine= Show container\n"
, program_invocation_short_name, arg_depth);
}
@@ -639,15 +677,17 @@ static int parse_argv(int argc, char *argv[]) {
{ "cpu", optional_argument, NULL, ARG_CPU_TYPE },
{ "order", required_argument, NULL, ARG_ORDER },
{ "recursive", required_argument, NULL, ARG_RECURSIVE },
+ { "machine", required_argument, NULL, 'M' },
{}
};
+ bool recursive_unset = false;
int c, r;
assert(argc >= 1);
assert(argv);
- while ((c = getopt_long(argc, argv, "hptcmin:brd:k", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hptcmin:brd:kPM:", options, NULL)) >= 0)
switch (c) {
@@ -656,9 +696,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_CPU_TYPE:
if (optarg) {
@@ -748,7 +786,11 @@ static int parse_argv(int argc, char *argv[]) {
break;
case 'k':
- arg_kernel_threads = true;
+ arg_count = COUNT_ALL_PROCESSES;
+ break;
+
+ case 'P':
+ arg_count = COUNT_USERSPACE_PROCESSES;
break;
case ARG_RECURSIVE:
@@ -759,6 +801,11 @@ static int parse_argv(int argc, char *argv[]) {
}
arg_recursive = r;
+ recursive_unset = r == 0;
+ break;
+
+ case 'M':
+ arg_machine = optarg;
break;
case '?':
@@ -773,9 +820,65 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (recursive_unset && arg_count == COUNT_PIDS) {
+ log_error("Non-recursive counting is only supported when counting processes, not tasks. Use -P or -k.");
+ return -EINVAL;
+ }
+
return 1;
}
+static const char* counting_what(void) {
+ if (arg_count == COUNT_PIDS)
+ return "tasks";
+ else if (arg_count == COUNT_ALL_PROCESSES)
+ return "all processes (incl. kernel)";
+ else
+ return "userspace processes (excl. kernel)";
+}
+
+static int get_cgroup_root(char **ret) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ _cleanup_free_ char *unit = NULL, *path = NULL;
+ const char *m;
+ int r;
+
+ if (!arg_machine) {
+ r = cg_get_root_path(ret);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get root control group path: %m");
+
+ return 0;
+ }
+
+ m = strjoina("/run/systemd/machines/", arg_machine);
+ r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load machine data: %m");
+
+ path = unit_dbus_path_from_name(unit);
+ if (!path)
+ return log_oom();
+
+ r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ unit_dbus_interface_from_name(unit),
+ "ControlGroup",
+ &error,
+ ret);
+ if (r < 0)
+ return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
int r;
Hashmap *a = NULL, *b = NULL;
@@ -783,15 +886,24 @@ int main(int argc, char *argv[]) {
usec_t last_refresh = 0;
bool quit = false, immediate_refresh = false;
_cleanup_free_ char *root = NULL;
+ CGroupMask mask;
log_parse_environment();
log_open();
+ r = cg_mask_supported(&mask);
+ if (r < 0) {
+ log_error_errno(r, "Failed to determine supported controllers: %m");
+ goto finish;
+ }
+
+ arg_count = (mask & CGROUP_MASK_PIDS) ? COUNT_PIDS : COUNT_USERSPACE_PROCESSES;
+
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
- r = cg_get_root_path(&root);
+ r = get_cgroup_root(&root);
if (r < 0) {
log_error_errno(r, "Failed to get root control group path: %m");
goto finish;
@@ -899,15 +1011,26 @@ int main(int argc, char *argv[]) {
break;
case 'k':
- arg_kernel_threads = !arg_kernel_threads;
- fprintf(stdout, "\nCounting kernel threads: %s.", yes_no(arg_kernel_threads));
+ arg_count = arg_count != COUNT_ALL_PROCESSES ? COUNT_ALL_PROCESSES : COUNT_PIDS;
+ fprintf(stdout, "\nCounting: %s.", counting_what());
+ fflush(stdout);
+ sleep(1);
+ break;
+
+ case 'P':
+ arg_count = arg_count != COUNT_USERSPACE_PROCESSES ? COUNT_USERSPACE_PROCESSES : COUNT_PIDS;
+ fprintf(stdout, "\nCounting: %s.", counting_what());
fflush(stdout);
sleep(1);
break;
case 'r':
- arg_recursive = !arg_recursive;
- fprintf(stdout, "\nRecursive task counting: %s", yes_no(arg_recursive));
+ if (arg_count == COUNT_PIDS)
+ fprintf(stdout, "\n\aCannot toggle recursive counting, not available in task counting mode.");
+ else {
+ arg_recursive = !arg_recursive;
+ fprintf(stdout, "\nRecursive process counting: %s", yes_no(arg_recursive));
+ }
fflush(stdout);
sleep(1);
break;
@@ -938,10 +1061,15 @@ int main(int argc, char *argv[]) {
case '?':
case 'h':
+
+#define ON ANSI_HIGHLIGHT
+#define OFF ANSI_NORMAL
+
fprintf(stdout,
- "\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n"
+ "\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks/procs; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n"
"\t<" ON "+" OFF "> Inc. delay; <" ON "-" OFF "> Dec. delay; <" ON "%%" OFF "> Toggle time; <" ON "SPACE" OFF "> Refresh\n"
- "\t<" ON "k" OFF "> Count kernel threads; <" ON "r" OFF "> Count recursively; <" ON "q" OFF "> Quit");
+ "\t<" ON "P" OFF "> Toggle count userspace processes; <" ON "k" OFF "> Toggle count all processes\n"
+ "\t<" ON "r" OFF "> Count processes recursively; <" ON "q" OFF "> Quit");
fflush(stdout);
sleep(3);
break;
diff --git a/src/core/automount.c b/src/core/automount.c
index c88e3311bc..e0535ec201 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -774,8 +774,9 @@ static int automount_stop(Unit *u) {
static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
Automount *a = AUTOMOUNT(u);
- void *p;
Iterator i;
+ void *p;
+ int r;
assert(a);
assert(f);
@@ -790,15 +791,9 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
SET_FOREACH(p, a->expire_tokens, i)
unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p));
- if (a->pipe_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, a->pipe_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
- }
+ r = unit_serialize_item_fd(u, f, fds, "pipe-fd", a->pipe_fd);
+ if (r < 0)
+ return r;
return 0;
}
@@ -1024,15 +1019,6 @@ static bool automount_supported(void) {
return supported;
}
-static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
- [AUTOMOUNT_DEAD] = "dead",
- [AUTOMOUNT_WAITING] = "waiting",
- [AUTOMOUNT_RUNNING] = "running",
- [AUTOMOUNT_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
-
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
[AUTOMOUNT_SUCCESS] = "success",
[AUTOMOUNT_FAILURE_RESOURCES] = "resources"
diff --git a/src/core/automount.h b/src/core/automount.h
index 2a50fef68d..43ea9f772d 100644
--- a/src/core/automount.h
+++ b/src/core/automount.h
@@ -25,15 +25,6 @@ typedef struct Automount Automount;
#include "unit.h"
-typedef enum AutomountState {
- AUTOMOUNT_DEAD,
- AUTOMOUNT_WAITING,
- AUTOMOUNT_RUNNING,
- AUTOMOUNT_FAILED,
- _AUTOMOUNT_STATE_MAX,
- _AUTOMOUNT_STATE_INVALID = -1
-} AutomountState;
-
typedef enum AutomountResult {
AUTOMOUNT_SUCCESS,
AUTOMOUNT_FAILURE_RESOURCES,
@@ -66,8 +57,5 @@ extern const UnitVTable automount_vtable;
int automount_update_mount(Automount *a, MountState old_state, MountState state);
-const char* automount_state_to_string(AutomountState i) _const_;
-AutomountState automount_state_from_string(const char *s) _pure_;
-
const char* automount_result_to_string(AutomountResult i) _const_;
AutomountResult automount_result_from_string(const char *s) _pure_;
diff --git a/src/core/busname.c b/src/core/busname.c
index 4020e9dd3c..b85fce5f8d 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -585,6 +585,12 @@ static void busname_enter_running(BusName *n) {
}
if (!pending) {
+ if (!UNIT_ISSET(n->service)) {
+ log_unit_error(UNIT(n), "Service to activate vanished, refusing activation.");
+ r = -ENOENT;
+ goto fail;
+ }
+
r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
if (r < 0)
goto fail;
@@ -656,6 +662,7 @@ static int busname_stop(Unit *u) {
static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
BusName *n = BUSNAME(u);
+ int r;
assert(n);
assert(f);
@@ -667,15 +674,9 @@ static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
if (n->control_pid > 0)
unit_serialize_item_format(u, f, "control-pid", PID_FMT, n->control_pid);
- if (n->starter_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, n->starter_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
- }
+ r = unit_serialize_item_fd(u, f, fds, "starter-fd", n->starter_fd);
+ if (r < 0)
+ return r;
return 0;
}
@@ -991,19 +992,6 @@ static bool busname_supported(void) {
return supported;
}
-static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
- [BUSNAME_DEAD] = "dead",
- [BUSNAME_MAKING] = "making",
- [BUSNAME_REGISTERED] = "registered",
- [BUSNAME_LISTENING] = "listening",
- [BUSNAME_RUNNING] = "running",
- [BUSNAME_SIGTERM] = "sigterm",
- [BUSNAME_SIGKILL] = "sigkill",
- [BUSNAME_FAILED] = "failed",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
-
static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
[BUSNAME_SUCCESS] = "success",
[BUSNAME_FAILURE_RESOURCES] = "resources",
diff --git a/src/core/busname.h b/src/core/busname.h
index 69528a2aef..1bc3290596 100644
--- a/src/core/busname.h
+++ b/src/core/busname.h
@@ -24,20 +24,6 @@
typedef struct BusName BusName;
typedef struct BusNamePolicy BusNamePolicy;
-
-typedef enum BusNameState {
- BUSNAME_DEAD,
- BUSNAME_MAKING,
- BUSNAME_REGISTERED,
- BUSNAME_LISTENING,
- BUSNAME_RUNNING,
- BUSNAME_SIGTERM,
- BUSNAME_SIGKILL,
- BUSNAME_FAILED,
- _BUSNAME_STATE_MAX,
- _BUSNAME_STATE_INVALID = -1
-} BusNameState;
-
typedef enum BusNameResult {
BUSNAME_SUCCESS,
BUSNAME_FAILURE_RESOURCES,
@@ -77,8 +63,5 @@ struct BusName {
extern const UnitVTable busname_vtable;
-const char* busname_state_to_string(BusNameState i) _const_;
-BusNameState busname_state_from_string(const char *s) _pure_;
-
const char* busname_result_to_string(BusNameResult i) _const_;
BusNameResult busname_result_from_string(const char *s) _pure_;
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index baa7cc5488..0c790c33da 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -22,10 +22,11 @@
#include <fcntl.h>
#include <fnmatch.h>
-#include "process-util.h"
+#include "cgroup-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "special.h"
-#include "cgroup-util.h"
+
#include "cgroup.h"
#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
@@ -36,13 +37,18 @@ void cgroup_context_init(CGroupContext *c) {
/* Initialize everything to the kernel defaults, assuming the
* structure is preinitialized to 0 */
- c->cpu_shares = (unsigned long) -1;
- c->startup_cpu_shares = (unsigned long) -1;
+ c->cpu_shares = CGROUP_CPU_SHARES_INVALID;
+ c->startup_cpu_shares = CGROUP_CPU_SHARES_INVALID;
+ c->cpu_quota_per_sec_usec = USEC_INFINITY;
+
c->memory_limit = (uint64_t) -1;
- c->blockio_weight = (unsigned long) -1;
- c->startup_blockio_weight = (unsigned long) -1;
- c->cpu_quota_per_sec_usec = USEC_INFINITY;
+ c->blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID;
+ c->startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID;
+
+ c->tasks_max = (uint64_t) -1;
+
+ c->netclass_type = CGROUP_NETCLASS_TYPE_NONE;
}
void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
@@ -100,23 +106,27 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sCPUAccounting=%s\n"
"%sBlockIOAccounting=%s\n"
"%sMemoryAccounting=%s\n"
- "%sCPUShares=%lu\n"
- "%sStartupCPUShares=%lu\n"
+ "%sTasksAccounting=%s\n"
+ "%sCPUShares=%" PRIu64 "\n"
+ "%sStartupCPUShares=%" PRIu64 "\n"
"%sCPUQuotaPerSecSec=%s\n"
- "%sBlockIOWeight=%lu\n"
- "%sStartupBlockIOWeight=%lu\n"
+ "%sBlockIOWeight=%" PRIu64 "\n"
+ "%sStartupBlockIOWeight=%" PRIu64 "\n"
"%sMemoryLimit=%" PRIu64 "\n"
+ "%sTasksMax=%" PRIu64 "\n"
"%sDevicePolicy=%s\n"
"%sDelegate=%s\n",
prefix, yes_no(c->cpu_accounting),
prefix, yes_no(c->blockio_accounting),
prefix, yes_no(c->memory_accounting),
+ prefix, yes_no(c->tasks_accounting),
prefix, c->cpu_shares,
prefix, c->startup_cpu_shares,
prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
prefix, c->blockio_weight,
prefix, c->startup_blockio_weight,
prefix, c->memory_limit,
+ prefix, c->tasks_max,
prefix, cgroup_device_policy_to_string(c->device_policy),
prefix, yes_no(c->delegate));
@@ -129,7 +139,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
LIST_FOREACH(device_weights, w, c->blockio_device_weights)
fprintf(f,
- "%sBlockIODeviceWeight=%s %lu",
+ "%sBlockIODeviceWeight=%s %" PRIu64,
prefix,
w->path,
w->weight);
@@ -283,7 +293,7 @@ fail:
return -errno;
}
-void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) {
+void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, uint32_t netclass, ManagerState state) {
bool is_root;
int r;
@@ -305,11 +315,11 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
* and missing cgroups, i.e. EROFS and ENOENT. */
if ((mask & CGROUP_MASK_CPU) && !is_root) {
- char buf[MAX(DECIMAL_STR_MAX(unsigned long), DECIMAL_STR_MAX(usec_t)) + 1];
+ char buf[MAX(DECIMAL_STR_MAX(uint64_t), DECIMAL_STR_MAX(usec_t)) + 1];
- sprintf(buf, "%lu\n",
- IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != (unsigned long) -1 ? c->startup_cpu_shares :
- c->cpu_shares != (unsigned long) -1 ? c->cpu_shares : 1024);
+ sprintf(buf, "%" PRIu64 "\n",
+ IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->startup_cpu_shares :
+ 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,
@@ -332,15 +342,15 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
}
if (mask & CGROUP_MASK_BLKIO) {
- char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1,
- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1,
- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
+ char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1,
+ DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
CGroupBlockIODeviceWeight *w;
CGroupBlockIODeviceBandwidth *b;
if (!is_root) {
- sprintf(buf, "%lu\n", IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != (unsigned long) -1 ? c->startup_blockio_weight :
- c->blockio_weight != (unsigned long) -1 ? c->blockio_weight : 1000);
+ sprintf(buf, "%" PRIu64 "\n",
+ IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->startup_blockio_weight :
+ c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT);
r = cg_set_attribute("blkio", path, "blkio.weight", buf);
if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
@@ -354,7 +364,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
if (r < 0)
continue;
- sprintf(buf, "%u:%u %lu", major(dev), minor(dev), w->weight);
+ 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,
@@ -466,6 +476,32 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
}
}
+
+ if ((mask & CGROUP_MASK_PIDS) && !is_root) {
+
+ if (c->tasks_max != (uint64_t) -1) {
+ char buf[DECIMAL_STR_MAX(uint64_t) + 2];
+
+ sprintf(buf, "%" PRIu64 "\n", c->tasks_max);
+ r = cg_set_attribute("pids", path, "pids.max", buf);
+ } else
+ 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,
+ "Failed to set pids.max on %s: %m", path);
+ }
+
+ if (mask & CGROUP_MASK_NET_CLS) {
+ char buf[DECIMAL_STR_MAX(uint32_t)];
+
+ sprintf(buf, "%" PRIu32, netclass);
+
+ 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,
+ "Failed to set net_cls.classid on %s: %m", path);
+ }
}
CGroupMask cgroup_context_get_mask(CGroupContext *c) {
@@ -474,14 +510,14 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) {
/* Figure out which controllers we need */
if (c->cpu_accounting ||
- c->cpu_shares != (unsigned long) -1 ||
- c->startup_cpu_shares != (unsigned long) -1 ||
+ c->cpu_shares != CGROUP_CPU_SHARES_INVALID ||
+ c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID ||
c->cpu_quota_per_sec_usec != USEC_INFINITY)
mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU;
if (c->blockio_accounting ||
- c->blockio_weight != (unsigned long) -1 ||
- c->startup_blockio_weight != (unsigned long) -1 ||
+ c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
+ c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
c->blockio_device_weights ||
c->blockio_device_bandwidths)
mask |= CGROUP_MASK_BLKIO;
@@ -494,6 +530,13 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) {
c->device_policy != CGROUP_AUTO)
mask |= CGROUP_MASK_DEVICES;
+ if (c->tasks_accounting ||
+ c->tasks_max != (uint64_t) -1)
+ mask |= CGROUP_MASK_PIDS;
+
+ if (c->netclass_type != CGROUP_NETCLASS_TYPE_NONE)
+ mask |= CGROUP_MASK_NET_CLS;
+
return mask;
}
@@ -861,6 +904,103 @@ static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask) {
return u->cgroup_realized && u->cgroup_realized_mask == target_mask;
}
+static int unit_find_free_netclass_cgroup(Unit *u, uint32_t *ret) {
+
+ uint32_t start, i;
+ Manager *m;
+
+ assert(u);
+
+ m = u->manager;
+
+ i = start = m->cgroup_netclass_registry_last;
+
+ do {
+ i++;
+
+ if (!hashmap_get(m->cgroup_netclass_registry, UINT_TO_PTR(i))) {
+ m->cgroup_netclass_registry_last = i;
+ *ret = i;
+ return 0;
+ }
+
+ if (i == UINT32_MAX)
+ i = CGROUP_NETCLASS_FIXED_MAX;
+
+ } while (i != start);
+
+ return -ENOBUFS;
+}
+
+int unit_add_to_netclass_cgroup(Unit *u) {
+
+ CGroupContext *cc;
+ Unit *first;
+ void *key;
+ int r;
+
+ assert(u);
+
+ cc = unit_get_cgroup_context(u);
+ if (!cc)
+ return 0;
+
+ switch (cc->netclass_type) {
+ case CGROUP_NETCLASS_TYPE_NONE:
+ return 0;
+
+ case CGROUP_NETCLASS_TYPE_FIXED:
+ u->cgroup_netclass_id = cc->netclass_id;
+ break;
+
+ case CGROUP_NETCLASS_TYPE_AUTO:
+ /* Allocate a new ID in case it was requested and not done yet */
+ if (u->cgroup_netclass_id == 0) {
+ r = unit_find_free_netclass_cgroup(u, &u->cgroup_netclass_id);
+ if (r < 0)
+ return r;
+
+ log_debug("Dynamically assigned netclass cgroup id %" PRIu32 " to %s", u->cgroup_netclass_id, u->id);
+ }
+
+ break;
+ }
+
+ r = hashmap_ensure_allocated(&u->manager->cgroup_netclass_registry, &trivial_hash_ops);
+ if (r < 0)
+ return r;
+
+ key = UINT32_TO_PTR(u->cgroup_netclass_id);
+ first = hashmap_get(u->manager->cgroup_netclass_registry, key);
+
+ if (first) {
+ LIST_PREPEND(cgroup_netclass, first, u);
+ return hashmap_replace(u->manager->cgroup_netclass_registry, key, u);
+ }
+
+ return hashmap_put(u->manager->cgroup_netclass_registry, key, u);
+}
+
+int unit_remove_from_netclass_cgroup(Unit *u) {
+
+ Unit *head;
+ void *key;
+
+ assert(u);
+
+ key = UINT32_TO_PTR(u->cgroup_netclass_id);
+
+ LIST_FIND_HEAD(cgroup_netclass, u, head);
+ LIST_REMOVE(cgroup_netclass, head, u);
+
+ if (head)
+ return hashmap_replace(u->manager->cgroup_netclass_registry, key, head);
+
+ hashmap_remove(u->manager->cgroup_netclass_registry, key);
+
+ return 0;
+}
+
/* Check if necessary controllers and attributes for a unit are in place.
*
* If so, do nothing.
@@ -896,7 +1036,7 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
return r;
/* Finally, apply the necessary attributes. */
- cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, state);
+ cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, u->cgroup_netclass_id, state);
return 0;
}
@@ -1459,6 +1599,28 @@ int unit_get_memory_current(Unit *u, uint64_t *ret) {
return safe_atou64(v, ret);
}
+int unit_get_tasks_current(Unit *u, uint64_t *ret) {
+ _cleanup_free_ char *v = NULL;
+ int r;
+
+ assert(u);
+ assert(ret);
+
+ if (!u->cgroup_path)
+ return -ENODATA;
+
+ if ((u->cgroup_realized_mask & CGROUP_MASK_PIDS) == 0)
+ return -ENODATA;
+
+ r = cg_get_attribute("pids", u->cgroup_path, "pids.current", &v);
+ if (r == -ENOENT)
+ return -ENODATA;
+ if (r < 0)
+ return r;
+
+ return safe_atou64(v, ret);
+}
+
static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) {
_cleanup_free_ char *v = NULL;
uint64_t ns;
@@ -1532,6 +1694,32 @@ bool unit_cgroup_delegate(Unit *u) {
return c->delegate;
}
+void unit_invalidate_cgroup(Unit *u, CGroupMask m) {
+ assert(u);
+
+ if (!UNIT_HAS_CGROUP_CONTEXT(u))
+ return;
+
+ if (m == 0)
+ return;
+
+ if ((u->cgroup_realized_mask & m) == 0)
+ return;
+
+ u->cgroup_realized_mask &= ~m;
+ unit_add_to_cgroup_queue(u);
+}
+
+void manager_invalidate_startup_units(Manager *m) {
+ Iterator i;
+ Unit *u;
+
+ assert(m);
+
+ SET_FOREACH(u, m->startup_units, i)
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_BLKIO);
+}
+
static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
[CGROUP_AUTO] = "auto",
[CGROUP_CLOSED] = "closed",
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 438f5bf50f..457544b49f 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -26,6 +26,11 @@
#include "list.h"
#include "time-util.h"
+/* Maximum value for fixed (manual) net class ID assignment,
+ * and also the value at which the range of automatic assignments starts
+ */
+#define CGROUP_NETCLASS_FIXED_MAX UINT32_C(65535)
+
typedef struct CGroupContext CGroupContext;
typedef struct CGroupDeviceAllow CGroupDeviceAllow;
typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight;
@@ -47,6 +52,17 @@ typedef enum CGroupDevicePolicy {
_CGROUP_DEVICE_POLICY_INVALID = -1
} CGroupDevicePolicy;
+typedef enum CGroupNetClassType {
+ /* Default - do not assign a net class */
+ CGROUP_NETCLASS_TYPE_NONE,
+
+ /* Automatically assign a net class */
+ CGROUP_NETCLASS_TYPE_AUTO,
+
+ /* Assign the net class that was provided by the user */
+ CGROUP_NETCLASS_TYPE_FIXED,
+} CGroupNetClassType;
+
struct CGroupDeviceAllow {
LIST_FIELDS(CGroupDeviceAllow, device_allow);
char *path;
@@ -58,7 +74,7 @@ struct CGroupDeviceAllow {
struct CGroupBlockIODeviceWeight {
LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights);
char *path;
- unsigned long weight;
+ uint64_t weight;
};
struct CGroupBlockIODeviceBandwidth {
@@ -72,13 +88,14 @@ struct CGroupContext {
bool cpu_accounting;
bool blockio_accounting;
bool memory_accounting;
+ bool tasks_accounting;
- unsigned long cpu_shares;
- unsigned long startup_cpu_shares;
+ uint64_t cpu_shares;
+ uint64_t startup_cpu_shares;
usec_t cpu_quota_per_sec_usec;
- unsigned long blockio_weight;
- unsigned long startup_blockio_weight;
+ uint64_t blockio_weight;
+ uint64_t startup_blockio_weight;
LIST_HEAD(CGroupBlockIODeviceWeight, blockio_device_weights);
LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths);
@@ -87,6 +104,11 @@ struct CGroupContext {
CGroupDevicePolicy device_policy;
LIST_HEAD(CGroupDeviceAllow, device_allow);
+ CGroupNetClassType netclass_type;
+ uint32_t netclass_id;
+
+ uint64_t tasks_max;
+
bool delegate;
};
@@ -96,7 +118,7 @@ struct CGroupContext {
void cgroup_context_init(CGroupContext *c);
void cgroup_context_done(CGroupContext *c);
void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix);
-void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state);
+void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, uint32_t netclass_id, ManagerState state);
CGroupMask cgroup_context_get_mask(CGroupContext *c);
@@ -124,6 +146,9 @@ int unit_watch_cgroup(Unit *u);
int unit_attach_pids_to_cgroup(Unit *u);
+int unit_add_to_netclass_cgroup(Unit *u);
+int unit_remove_from_netclass_cgroup(Unit *u);
+
int manager_setup_cgroup(Manager *m);
void manager_shutdown_cgroup(Manager *m, bool delete);
@@ -137,6 +162,7 @@ int unit_search_main_pid(Unit *u, pid_t *ret);
int unit_watch_all_pids(Unit *u);
int unit_get_memory_current(Unit *u, uint64_t *ret);
+int unit_get_tasks_current(Unit *u, uint64_t *ret);
int unit_get_cpu_usage(Unit *u, nsec_t *ret);
int unit_reset_cpu_usage(Unit *u);
@@ -145,5 +171,9 @@ bool unit_cgroup_delegate(Unit *u);
int unit_notify_cgroup_empty(Unit *u);
int manager_notify_cgroup_empty(Manager *m, const char *group);
+void unit_invalidate_cgroup(Unit *u, CGroupMask m);
+
+void manager_invalidate_startup_units(Manager *m);
+
const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index ba2f4e53b9..f334dc928d 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -133,34 +133,16 @@ static int property_get_device_allow(
return sd_bus_message_close_container(reply);
}
-static int property_get_ulong_as_u64(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- unsigned long *ul = userdata;
-
- assert(bus);
- assert(reply);
- assert(ul);
-
- return sd_bus_message_append(reply, "t", *ul == (unsigned long) -1 ? (uint64_t) -1 : (uint64_t) *ul);
-}
-
const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
- SD_BUS_PROPERTY("CPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, cpu_shares), 0),
- SD_BUS_PROPERTY("StartupCPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_cpu_shares), 0),
+ SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
+ SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
- SD_BUS_PROPERTY("BlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, blockio_weight), 0),
- SD_BUS_PROPERTY("StartupBlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_blockio_weight), 0),
+ SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0),
+ SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0),
SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
@@ -168,6 +150,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
+ SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
+ SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
SD_BUS_VTABLE_END
};
@@ -228,56 +212,52 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->cpu_accounting = b;
- u->cgroup_realized_mask &= ~CGROUP_MASK_CPUACCT;
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU);
unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
}
return 1;
} else if (streq(name, "CPUShares")) {
- uint64_t u64;
- unsigned long ul;
+ uint64_t shares;
- r = sd_bus_message_read(message, "t", &u64);
+ r = sd_bus_message_read(message, "t", &shares);
if (r < 0)
return r;
- if (u64 == (uint64_t) -1)
- ul = (unsigned long) -1;
- else {
- ul = (unsigned long) u64;
- if (ul <= 0 || (uint64_t) ul != u64)
- return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
- }
+ if (!CGROUP_CPU_SHARES_IS_OK(shares))
+ return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
if (mode != UNIT_CHECK) {
- c->cpu_shares = ul;
- u->cgroup_realized_mask &= ~CGROUP_MASK_CPU;
- unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
+ c->cpu_shares = shares;
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
+
+ if (shares == CGROUP_CPU_SHARES_INVALID)
+ unit_write_drop_in_private(u, mode, name, "CPUShares=");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares);
}
return 1;
} else if (streq(name, "StartupCPUShares")) {
- uint64_t u64;
- unsigned long ul;
+ uint64_t shares;
- r = sd_bus_message_read(message, "t", &u64);
+ r = sd_bus_message_read(message, "t", &shares);
if (r < 0)
return r;
- if (u64 == (uint64_t) -1)
- ul = (unsigned long) -1;
- else {
- ul = (unsigned long) u64;
- if (ul <= 0 || (uint64_t) ul != u64)
- return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
- }
+ if (!CGROUP_CPU_SHARES_IS_OK(shares))
+ return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
if (mode != UNIT_CHECK) {
- c->startup_cpu_shares = ul;
- u->cgroup_realized_mask &= ~CGROUP_MASK_CPU;
- unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul);
+ c->startup_cpu_shares = shares;
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
+
+ if (shares == CGROUP_CPU_SHARES_INVALID)
+ unit_write_drop_in_private(u, mode, name, "StartupCPUShares=");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares);
}
return 1;
@@ -294,7 +274,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->cpu_quota_per_sec_usec = u64;
- u->cgroup_realized_mask &= ~CGROUP_MASK_CPU;
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000));
}
@@ -309,56 +289,52 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->blockio_accounting = b;
- u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
+ unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
}
return 1;
} else if (streq(name, "BlockIOWeight")) {
- uint64_t u64;
- unsigned long ul;
+ uint64_t weight;
- r = sd_bus_message_read(message, "t", &u64);
+ r = sd_bus_message_read(message, "t", &weight);
if (r < 0)
return r;
- if (u64 == (uint64_t) -1)
- ul = (unsigned long) -1;
- else {
- ul = (unsigned long) u64;
- if (ul < 10 || ul > 1000)
- return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
- }
+ if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
+ return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
if (mode != UNIT_CHECK) {
- c->blockio_weight = ul;
- u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
- unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
+ c->blockio_weight = weight;
+ unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
+
+ if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
+ unit_write_drop_in_private(u, mode, name, "BlockIOWeight=");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight);
}
return 1;
} else if (streq(name, "StartupBlockIOWeight")) {
- uint64_t u64;
- unsigned long ul;
+ uint64_t weight;
- r = sd_bus_message_read(message, "t", &u64);
+ r = sd_bus_message_read(message, "t", &weight);
if (r < 0)
return r;
- if (u64 == (uint64_t) -1)
- ul = (unsigned long) -1;
- else {
- ul = (unsigned long) u64;
- if (ul < 10 || ul > 1000)
- return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
- }
+ if (CGROUP_BLKIO_WEIGHT_IS_OK(weight))
+ return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
if (mode != UNIT_CHECK) {
- c->startup_blockio_weight = ul;
- u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
- unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul);
+ c->startup_blockio_weight = weight;
+ unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
+
+ if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
+ unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight=");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight);
}
return 1;
@@ -427,7 +403,7 @@ int bus_cgroup_set_property(
cgroup_context_free_blockio_device_bandwidth(c, a);
}
- u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
+ unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
f = open_memstream(&buf, &size);
if (!f)
@@ -453,17 +429,16 @@ int bus_cgroup_set_property(
} else if (streq(name, "BlockIODeviceWeight")) {
const char *path;
- uint64_t u64;
+ uint64_t weight;
unsigned n = 0;
r = sd_bus_message_enter_container(message, 'a', "(st)");
if (r < 0)
return r;
- while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
- unsigned long ul = u64;
+ while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
- if (ul < 10 || ul > 1000)
+ if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
if (mode != UNIT_CHECK) {
@@ -489,7 +464,7 @@ int bus_cgroup_set_property(
LIST_PREPEND(device_weights,c->blockio_device_weights, a);
}
- a->weight = ul;
+ a->weight = weight;
}
n++;
@@ -510,7 +485,7 @@ int bus_cgroup_set_property(
cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
}
- u->cgroup_realized_mask &= ~CGROUP_MASK_BLKIO;
+ unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
f = open_memstream(&buf, &size);
if (!f)
@@ -518,7 +493,7 @@ int bus_cgroup_set_property(
fputs("BlockIODeviceWeight=\n", f);
LIST_FOREACH(device_weights, a, c->blockio_device_weights)
- fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
+ fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
fflush(f);
unit_write_drop_in_private(u, mode, name, buf);
@@ -535,7 +510,7 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->memory_accounting = b;
- u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY;
+ unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
}
@@ -550,8 +525,12 @@ int bus_cgroup_set_property(
if (mode != UNIT_CHECK) {
c->memory_limit = limit;
- u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY;
- unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
+ unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
+
+ if (limit == (uint64_t) -1)
+ unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit);
}
return 1;
@@ -572,7 +551,7 @@ int bus_cgroup_set_property(
char *buf;
c->device_policy = p;
- u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICES;
+ unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
buf = strjoina("DevicePolicy=", policy);
unit_write_drop_in_private(u, mode, name, buf);
@@ -651,7 +630,7 @@ int bus_cgroup_set_property(
cgroup_context_free_device_allow(c, c->device_allow);
}
- u->cgroup_realized_mask &= ~CGROUP_MASK_DEVICES;
+ unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
f = open_memstream(&buf, &size);
if (!f)
@@ -667,6 +646,39 @@ int bus_cgroup_set_property(
return 1;
+ } else if (streq(name, "TasksAccounting")) {
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->tasks_accounting = b;
+ unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
+ unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no");
+ }
+
+ return 1;
+
+ } else if (streq(name, "TasksMax")) {
+ uint64_t limit;
+
+ r = sd_bus_message_read(message, "t", &limit);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->tasks_max = limit;
+ unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
+
+ if (limit == (uint64_t) -1)
+ unit_write_drop_in_private(u, mode, name, "TasksMax=infinity");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit);
+ }
+
+ return 1;
}
if (u->transient && u->load_state == UNIT_STUB) {
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index ed55fcfca2..436229330e 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -83,45 +83,6 @@ static int property_get_environment_files(
return sd_bus_message_close_container(reply);
}
-static int property_get_rlimit(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- struct rlimit *rl;
- uint64_t u;
- rlim_t x;
-
- assert(bus);
- assert(reply);
- assert(userdata);
-
- rl = *(struct rlimit**) userdata;
- if (rl)
- x = rl->rlim_max;
- else {
- struct rlimit buf = {};
- int z;
-
- z = rlimit_from_string(property);
- assert(z >= 0);
-
- getrlimit(z, &buf);
- x = buf.rlim_max;
- }
-
- /* rlim_t might have different sizes, let's map
- * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
- * all archs */
- u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
-
- return sd_bus_message_append(reply, "t", u);
-}
-
static int property_get_oom_score_adjust(
sd_bus *bus,
const char *path,
@@ -595,28 +556,91 @@ static int property_get_address_families(
return sd_bus_message_close_container(reply);
}
+static int property_get_working_directory(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+ const char *wd;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ if (c->working_directory_home)
+ wd = "~";
+ else
+ wd = c->working_directory;
+
+ if (c->working_directory_missing_ok)
+ wd = strjoina("!", wd);
+
+ return sd_bus_message_append(reply, "s", wd);
+}
+
+static int property_get_syslog_level(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ return sd_bus_message_append(reply, "i", LOG_PRI(c->syslog_priority));
+}
+
+static int property_get_syslog_facility(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority));
+}
+
const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -637,6 +661,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -829,7 +855,64 @@ int bus_exec_context_set_transient_property(
}
return 1;
+ } else if (streq(name, "SyslogIdentifier")) {
+ const char *id;
+
+ r = sd_bus_message_read(message, "s", &id);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ if (isempty(id)) {
+ c->syslog_identifier = mfree(c->syslog_identifier);
+ } else {
+ char *t;
+
+ t = strdup(id);
+ if (!t)
+ return -ENOMEM;
+
+ free(c->syslog_identifier);
+ c->syslog_identifier = t;
+ }
+
+ unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
+ }
+
+ return 1;
+ } else if (streq(name, "SyslogLevel")) {
+ int level;
+
+ r = sd_bus_message_read(message, "i", &level);
+ if (r < 0)
+ return r;
+
+ if (!log_level_is_valid(level))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
+
+ if (mode != UNIT_CHECK) {
+ c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
+ unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i\n", level);
+ }
+
+ return 1;
+ } else if (streq(name, "SyslogFacility")) {
+ int facility;
+
+ r = sd_bus_message_read(message, "i", &facility);
+ if (r < 0)
+ return r;
+
+ if (!log_facility_unshifted_is_valid(facility))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
+
+ if (mode != UNIT_CHECK) {
+ c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
+ unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i\n", facility);
+ }
+
+ return 1;
} else if (streq(name, "Nice")) {
int n;
@@ -847,27 +930,62 @@ int bus_exec_context_set_transient_property(
return 1;
- } else if (streq(name, "TTYPath")) {
- const char *tty;
+ } else if (STR_IN_SET(name, "TTYPath", "RootDirectory")) {
+ const char *s;
- r = sd_bus_message_read(message, "s", &tty);
+ r = sd_bus_message_read(message, "s", &s);
if (r < 0)
return r;
- if (!path_is_absolute(tty))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY device not absolute path");
+ if (!path_is_absolute(s))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s takes an absolute path", name);
if (mode != UNIT_CHECK) {
- char *t;
+ if (streq(name, "TTYPath"))
+ r = free_and_strdup(&c->tty_path, s);
+ else {
+ assert(streq(name, "RootDirectory"));
+ r = free_and_strdup(&c->root_directory, s);
+ }
+ if (r < 0)
+ return r;
- t = strdup(tty);
- if (!t)
- return -ENOMEM;
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ }
+
+ return 1;
+
+ } else if (streq(name, "WorkingDirectory")) {
+ const char *s;
+ bool missing_ok;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ if (s[0] == '-') {
+ missing_ok = true;
+ s++;
+ } else
+ missing_ok = false;
- free(c->tty_path);
- c->tty_path = t;
+ if (!streq(s, "~") && !path_is_absolute(s))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
- unit_write_drop_in_private_format(u, mode, name, "TTYPath=%s\n", tty);
+ if (mode != UNIT_CHECK) {
+ if (streq(s, "~")) {
+ c->working_directory = mfree(c->working_directory);
+ c->working_directory_home = true;
+ } else {
+ r = free_and_strdup(&c->working_directory, s);
+ if (r < 0)
+ return r;
+
+ c->working_directory_home = false;
+ }
+
+ c->working_directory_missing_ok = missing_ok;
+ unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s);
}
return 1;
@@ -933,37 +1051,10 @@ int bus_exec_context_set_transient_property(
return 1;
- } else if (streq(name, "IgnoreSIGPIPE")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->ignore_sigpipe = b;
-
- unit_write_drop_in_private_format(u, mode, name, "IgnoreSIGPIPE=%s\n", yes_no(b));
- }
-
- return 1;
-
- } else if (streq(name, "TTYVHangup")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->tty_vhangup = b;
-
- unit_write_drop_in_private_format(u, mode, name, "TTYVHangup=%s\n", yes_no(b));
- }
-
- return 1;
-
- } else if (streq(name, "TTYReset")) {
+ } else if (STR_IN_SET(name,
+ "IgnoreSIGPIPE", "TTYVHangup", "TTYReset",
+ "PrivateTmp", "PrivateDevices", "PrivateNetwork",
+ "NoNewPrivileges", "SyslogLevelPrefix")) {
int b;
r = sd_bus_message_read(message, "b", &b);
@@ -971,9 +1062,24 @@ int bus_exec_context_set_transient_property(
return r;
if (mode != UNIT_CHECK) {
- c->tty_reset = b;
-
- unit_write_drop_in_private_format(u, mode, name, "TTYReset=%s\n", yes_no(b));
+ if (streq(name, "IgnoreSIGPIPE"))
+ c->ignore_sigpipe = b;
+ else if (streq(name, "TTYVHangup"))
+ c->tty_vhangup = b;
+ else if (streq(name, "TTYReset"))
+ c->tty_reset = b;
+ else if (streq(name, "PrivateTmp"))
+ c->private_tmp = b;
+ else if (streq(name, "PrivateDevices"))
+ c->private_devices = b;
+ else if (streq(name, "PrivateNetwork"))
+ c->private_network = b;
+ else if (streq(name, "NoNewPrivileges"))
+ c->no_new_privileges = b;
+ else if (streq(name, "SyslogLevelPrefix"))
+ c->syslog_level_prefix = b;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, yes_no(b));
}
return 1;
@@ -1065,6 +1171,21 @@ int bus_exec_context_set_transient_property(
return 1;
+ } else if (streq(name, "TimerSlackNSec")) {
+
+ nsec_t n;
+
+ r = sd_bus_message_read(message, "t", &n);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->timer_slack_nsec = n;
+ unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n);
+ }
+
+ return 1;
+
} else if (rlimit_from_string(name) >= 0) {
uint64_t rl;
rlim_t x;
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 4e5d67fc19..9ddc65d10b 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -81,10 +81,21 @@ static int property_get_virtualization(
void *userdata,
sd_bus_error *error) {
+ int v;
+
assert(bus);
assert(reply);
- return sd_bus_message_append(reply, "s", virtualization_to_string(detect_virtualization()));
+ v = detect_virtualization();
+
+ /* Make sure to return the empty string when we detect no virtualization, as that is the API.
+ *
+ * https://github.com/systemd/systemd/issues/1423
+ */
+
+ return sd_bus_message_append(
+ reply, "s",
+ v == VIRTUALIZATION_NONE ? "" : virtualization_to_string(v));
}
static int property_get_architecture(
@@ -111,8 +122,7 @@ static int property_get_tainted(
void *userdata,
sd_bus_error *error) {
- char buf[sizeof("split-usr:mtab-not-symlink:cgroups-missing:local-hwclock:")] = "", *e = buf;
- _cleanup_free_ char *p = NULL;
+ char buf[sizeof("split-usr:cgroups-missing:local-hwclock:")] = "", *e = buf;
Manager *m = userdata;
assert(bus);
@@ -122,9 +132,6 @@ static int property_get_tainted(
if (m->taint_usr)
e = stpcpy(e, "split-usr:");
- if (readlink_malloc("/etc/mtab", &p) < 0)
- e = stpcpy(e, "mtab-not-symlink:");
-
if (access("/proc/cgroups", F_OK) < 0)
e = stpcpy(e, "cgroups-missing:");
@@ -1201,8 +1208,10 @@ static int method_exit(sd_bus_message *message, void *userdata, sd_bus_error *er
if (r < 0)
return r;
- if (m->running_as == MANAGER_SYSTEM)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
+ /* Exit() (in contrast to SetExitCode()) is actually allowed even if
+ * we are running on the host. It will fall back on reboot() in
+ * systemd-shutdown if it cannot do the exit() because it isn't a
+ * container. */
m->exit_code = MANAGER_EXIT;
@@ -1450,6 +1459,30 @@ static int method_unset_and_set_environment(sd_bus_message *message, void *userd
return sd_bus_reply_method_return(message, NULL);
}
+static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ uint8_t code;
+ Manager *m = userdata;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = mac_selinux_access_check(message, "exit", error);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read_basic(message, 'y', &code);
+ if (r < 0)
+ return r;
+
+ if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers.");
+
+ m->return_value = code;
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
@@ -1933,6 +1966,33 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0),
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
+ SD_BUS_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0),
+ SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -1986,6 +2046,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("AddDependencyUnitFiles", "asssbb", "a(sss)", method_add_dependency_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetExitCode", "y", NULL, method_set_exit_code, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("UnitNew", "so", 0),
SD_BUS_SIGNAL("UnitRemoved", "so", 0),
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index e1f3d56495..b636f8ba6a 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "async.h"
#include "strv.h"
#include "path-util.h"
#include "unit.h"
@@ -62,6 +63,8 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("USBFunctionDescriptors", "s", NULL, offsetof(Service, usb_function_descriptors), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("USBFunctionStrings", "s", NULL, offsetof(Service, usb_function_strings), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
@@ -118,6 +121,37 @@ static int bus_service_set_transient_property(
return 1;
+ } else if (STR_IN_SET(name,
+ "StandardInputFileDescriptor",
+ "StandardOutputFileDescriptor",
+ "StandardErrorFileDescriptor")) {
+ int fd;
+
+ r = sd_bus_message_read(message, "h", &fd);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ int copy;
+
+ copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (copy < 0)
+ return -errno;
+
+ if (streq(name, "StandardInputFileDescriptor")) {
+ asynchronous_close(s->stdin_fd);
+ s->stdin_fd = copy;
+ } else if (streq(name, "StandardOutputFileDescriptor")) {
+ asynchronous_close(s->stdout_fd);
+ s->stdout_fd = copy;
+ } else {
+ asynchronous_close(s->stderr_fd);
+ s->stderr_fd = copy;
+ }
+ }
+
+ return 1;
+
} else if (streq(name, "ExecStart")) {
unsigned n = 0;
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 02599a9e55..7444649f8b 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -68,6 +68,7 @@ static int property_get_listen(
case SOCKET_SPECIAL:
case SOCKET_MQUEUE:
case SOCKET_FIFO:
+ case SOCKET_USB_FUNCTION:
a = p->path;
break;
@@ -83,6 +84,25 @@ static int property_get_listen(
return sd_bus_message_close_container(reply);
}
+
+static int property_get_fdname(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Socket *s = SOCKET(userdata);
+
+ assert(bus);
+ assert(reply);
+ assert(s);
+
+ return sd_bus_message_append(reply, "s", socket_fdname(s));
+}
+
const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -94,6 +114,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Writable", "b", bus_property_get_bool, offsetof(Socket, writable), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KeepAliveTimeUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_time), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KeepAliveIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_interval), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -126,6 +147,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0),
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
+ SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index f9275ed935..cd88a87340 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -679,6 +679,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NetClass", "u", bus_property_get_unsigned, offsetof(Unit, cgroup_netclass_id), 0),
SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -736,6 +737,30 @@ static int property_get_current_memory(
return sd_bus_message_append(reply, "t", sz);
}
+static int property_get_current_tasks(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ uint64_t cn = (uint64_t) -1;
+ Unit *u = userdata;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(u);
+
+ r = unit_get_tasks_current(u, &cn);
+ if (r < 0 && r != -ENODATA)
+ log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m");
+
+ return sd_bus_message_append(reply, "t", cn);
+}
+
static int property_get_cpu_usage(
sd_bus *bus,
const char *path,
@@ -796,6 +821,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0),
SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
+ SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
SD_BUS_VTABLE_END
};
diff --git a/src/core/device.c b/src/core/device.c
index 0b54518691..a819ab8d4e 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -816,14 +816,6 @@ int device_found_node(Manager *m, const char *node, bool add, DeviceFound found,
return device_update_found_by_name(m, node, add, found, now);
}
-static const char* const device_state_table[_DEVICE_STATE_MAX] = {
- [DEVICE_DEAD] = "dead",
- [DEVICE_TENTATIVE] = "tentative",
- [DEVICE_PLUGGED] = "plugged",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
-
const UnitVTable device_vtable = {
.object_size = sizeof(Device),
.sections =
diff --git a/src/core/device.h b/src/core/device.h
index 10ab113176..da8737870b 100644
--- a/src/core/device.h
+++ b/src/core/device.h
@@ -23,16 +23,6 @@
typedef struct Device Device;
-/* We simply watch devices, we cannot plug/unplug them. That
- * simplifies the state engine greatly */
-typedef enum DeviceState {
- DEVICE_DEAD,
- DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */
- DEVICE_PLUGGED, /* announced by udev */
- _DEVICE_STATE_MAX,
- _DEVICE_STATE_INVALID = -1
-} DeviceState;
-
typedef enum DeviceFound {
DEVICE_NOT_FOUND = 0,
DEVICE_FOUND_UDEV = 1,
@@ -56,7 +46,4 @@ struct Device {
extern const UnitVTable device_vtable;
-const char* device_state_to_string(DeviceState i) _const_;
-DeviceState device_state_from_string(const char *s) _pure_;
-
int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now);
diff --git a/src/core/execute.c b/src/core/execute.c
index d1acda6682..d6217840c0 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -21,18 +21,18 @@
#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
+#include <glob.h>
+#include <grp.h>
+#include <poll.h>
#include <signal.h>
-#include <sys/socket.h>
-#include <sys/un.h>
+#include <string.h>
+#include <sys/personality.h>
#include <sys/prctl.h>
+#include <sys/socket.h>
#include <sys/stat.h>
-#include <grp.h>
-#include <poll.h>
-#include <glob.h>
+#include <sys/un.h>
+#include <unistd.h>
#include <utmpx.h>
-#include <sys/personality.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
@@ -51,35 +51,37 @@
#endif
#include "sd-messages.h"
-#include "rm-rf.h"
-#include "strv.h"
-#include "macro.h"
+
+#include "af-list.h"
+#include "async.h"
+#include "barrier.h"
+#include "bus-endpoint.h"
+#include "cap-list.h"
#include "capability.h"
-#include "util.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "namespace.h"
-#include "exit-status.h"
-#include "missing.h"
-#include "utmp-wtmp.h"
#include "def.h"
-#include "path-util.h"
#include "env-util.h"
-#include "fileio.h"
-#include "unit.h"
-#include "async.h"
-#include "selinux-util.h"
#include "errno-list.h"
-#include "af-list.h"
-#include "mkdir.h"
-#include "smack-util.h"
-#include "bus-endpoint.h"
-#include "cap-list.h"
+#include "exit-status.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "ioprio.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "namespace.h"
+#include "path-util.h"
#include "process-util.h"
-#include "terminal-util.h"
+#include "rm-rf.h"
+#include "securebits.h"
+#include "selinux-util.h"
#include "signal-util.h"
+#include "smack-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "unit.h"
+#include "util.h"
+#include "utmp-wtmp.h"
#ifdef HAVE_APPARMOR
#include "apparmor-util.h"
@@ -357,12 +359,28 @@ static int fixup_output(ExecOutput std_output, int socket_fd) {
return std_output;
}
-static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
+static int setup_input(
+ const ExecContext *context,
+ const ExecParameters *params,
+ int socket_fd) {
+
ExecInput i;
assert(context);
+ assert(params);
+
+ if (params->stdin_fd >= 0) {
+ if (dup2(params->stdin_fd, STDIN_FILENO) < 0)
+ return -errno;
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+ /* Try to make this the controlling tty, if it is a tty, and reset it */
+ (void) ioctl(STDIN_FILENO, TIOCSCTTY, context->std_input == EXEC_INPUT_TTY_FORCE);
+ (void) reset_terminal_fd(STDIN_FILENO, true);
+
+ return STDIN_FILENO;
+ }
+
+ i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
switch (i) {
@@ -399,16 +417,40 @@ static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty
}
}
-static int setup_output(Unit *unit, const ExecContext *context, int fileno, int socket_fd, const char *ident, bool apply_tty_stdin, uid_t uid, gid_t gid) {
+static int setup_output(
+ Unit *unit,
+ const ExecContext *context,
+ const ExecParameters *params,
+ int fileno,
+ int socket_fd,
+ const char *ident,
+ uid_t uid, gid_t gid) {
+
ExecOutput o;
ExecInput i;
int r;
assert(unit);
assert(context);
+ assert(params);
assert(ident);
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+ if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) {
+
+ if (dup2(params->stdout_fd, STDOUT_FILENO) < 0)
+ return -errno;
+
+ return STDOUT_FILENO;
+ }
+
+ if (fileno == STDERR_FILENO && params->stderr_fd >= 0) {
+ if (dup2(params->stderr_fd, STDERR_FILENO) < 0)
+ return -errno;
+
+ return STDERR_FILENO;
+ }
+
+ i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
o = fixup_output(context->std_output, socket_fd);
if (fileno == STDERR_FILENO) {
@@ -501,9 +543,9 @@ static int chown_terminal(int fd, uid_t uid) {
return 0;
}
-static int setup_confirm_stdio(int *_saved_stdin,
- int *_saved_stdout) {
- int fd = -1, saved_stdin, saved_stdout = -1, r;
+static int setup_confirm_stdio(int *_saved_stdin, int *_saved_stdout) {
+ _cleanup_close_ int fd = -1, saved_stdin = -1, saved_stdout = -1;
+ int r;
assert(_saved_stdin);
assert(_saved_stdout);
@@ -513,10 +555,8 @@ static int setup_confirm_stdio(int *_saved_stdin,
return -errno;
saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
- if (saved_stdout < 0) {
- r = errno;
- goto fail;
- }
+ if (saved_stdout < 0)
+ return -errno;
fd = acquire_terminal(
"/dev/console",
@@ -524,39 +564,33 @@ static int setup_confirm_stdio(int *_saved_stdin,
false,
false,
DEFAULT_CONFIRM_USEC);
- if (fd < 0) {
- r = fd;
- goto fail;
- }
+ if (fd < 0)
+ return fd;
r = chown_terminal(fd, getuid());
if (r < 0)
- goto fail;
+ return r;
- if (dup2(fd, STDIN_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
+ r = reset_terminal_fd(fd, true);
+ if (r < 0)
+ return r;
- if (dup2(fd, STDOUT_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
+ if (dup2(fd, STDIN_FILENO) < 0)
+ return -errno;
+
+ if (dup2(fd, STDOUT_FILENO) < 0)
+ return -errno;
if (fd >= 2)
safe_close(fd);
+ fd = -1;
*_saved_stdin = saved_stdin;
*_saved_stdout = saved_stdout;
- return 0;
-
-fail:
- safe_close(saved_stdout);
- safe_close(saved_stdin);
- safe_close(fd);
+ saved_stdin = saved_stdout = -1;
- return r;
+ return 0;
}
_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
@@ -576,9 +610,7 @@ _printf_(1, 2) static int write_confirm_message(const char *format, ...) {
return 0;
}
-static int restore_confirm_stdio(int *saved_stdin,
- int *saved_stdout) {
-
+static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) {
int r = 0;
assert(saved_stdin);
@@ -594,8 +626,8 @@ static int restore_confirm_stdio(int *saved_stdin,
if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
r = -errno;
- safe_close(*saved_stdin);
- safe_close(*saved_stdout);
+ *saved_stdin = safe_close(*saved_stdin);
+ *saved_stdout = safe_close(*saved_stdout);
return r;
}
@@ -629,15 +661,6 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_
* we avoid NSS lookups for gid=0. */
if (context->group || username) {
-
- if (context->group) {
- const char *g = context->group;
-
- r = get_group_creds(&g, &gid);
- if (r < 0)
- return r;
- }
-
/* First step, initialize groups from /etc/groups */
if (username && gid != 0) {
if (initgroups(username, gid) < 0)
@@ -777,10 +800,11 @@ static int setup_pam(
.appdata_ptr = NULL
};
+ _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
pam_handle_t *handle = NULL;
sigset_t old_ss;
int pam_code = PAM_SUCCESS;
- int err;
+ int err = 0;
char **e = NULL;
bool close_session = false;
pid_t pam_pid = 0, parent_pid;
@@ -797,6 +821,10 @@ static int setup_pam(
* daemon. We do things this way to ensure that the main PID
* of the daemon is the one we initially fork()ed. */
+ err = barrier_create(&barrier);
+ if (err < 0)
+ goto fail;
+
if (log_get_max_level() < LOG_DEBUG)
flags |= PAM_SILENT;
@@ -845,6 +873,7 @@ static int setup_pam(
/* The child's job is to reset the PAM session on
* termination */
+ barrier_set_role(&barrier, BARRIER_CHILD);
/* This string must fit in 10 chars (i.e. the length
* of "/sbin/init"), to look pretty in /bin/ps */
@@ -872,6 +901,11 @@ static int setup_pam(
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
goto child_finish;
+ /* Tell the parent that our setup is done. This is especially
+ * important regarding dropping privileges. Otherwise, unit
+ * setup might race against our setresuid(2) call. */
+ barrier_place(&barrier);
+
/* Check if our parent process might already have
* died? */
if (getppid() == parent_pid) {
@@ -907,6 +941,8 @@ static int setup_pam(
_exit(r);
}
+ barrier_set_role(&barrier, BARRIER_PARENT);
+
/* If the child was forked off successfully it will do all the
* cleanups, so forget about the handle here. */
handle = NULL;
@@ -918,6 +954,11 @@ static int setup_pam(
* might have opened it, but we don't want this fd around. */
closelog();
+ /* Synchronously wait for the child to initialize. We don't care for
+ * errors as we cannot recover. However, warn loudly if it happens. */
+ if (!barrier_place_and_sync(&barrier))
+ log_error("PAM initialization failed");
+
*pam_env = e;
e = NULL;
@@ -928,7 +969,7 @@ fail:
log_error("PAM failed: %s", pam_strerror(handle, pam_code));
err = -EPERM; /* PAM errors do not map to errno */
} else {
- err = log_error_errno(errno, "PAM failed: %m");
+ err = log_error_errno(err < 0 ? err : errno, "PAM failed: %m");
}
if (handle) {
@@ -1160,8 +1201,8 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
assert(idle_pipe);
- safe_close(idle_pipe[1]);
- safe_close(idle_pipe[2]);
+ idle_pipe[1] = safe_close(idle_pipe[1]);
+ idle_pipe[2] = safe_close(idle_pipe[2]);
if (idle_pipe[0] >= 0) {
int r;
@@ -1169,23 +1210,26 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
r = fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC);
if (idle_pipe[3] >= 0 && r == 0 /* timeout */) {
+ ssize_t n;
+
/* Signal systemd that we are bored and want to continue. */
- r = write(idle_pipe[3], "x", 1);
- if (r > 0)
+ n = write(idle_pipe[3], "x", 1);
+ if (n > 0)
/* Wait for systemd to react to the signal above. */
fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
}
- safe_close(idle_pipe[0]);
+ idle_pipe[0] = safe_close(idle_pipe[0]);
}
- safe_close(idle_pipe[3]);
+ idle_pipe[3] = safe_close(idle_pipe[3]);
}
static int build_environment(
const ExecContext *c,
unsigned n_fds,
+ char ** fd_names,
usec_t watchdog_usec,
const char *home,
const char *username,
@@ -1199,11 +1243,13 @@ static int build_environment(
assert(c);
assert(ret);
- our_env = new0(char*, 10);
+ our_env = new0(char*, 11);
if (!our_env)
return -ENOMEM;
if (n_fds > 0) {
+ _cleanup_free_ char *joined = NULL;
+
if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0)
return -ENOMEM;
our_env[n_env++] = x;
@@ -1211,6 +1257,15 @@ static int build_environment(
if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
return -ENOMEM;
our_env[n_env++] = x;
+
+ joined = strv_join(fd_names, ":");
+ if (!joined)
+ return -ENOMEM;
+
+ x = strjoin("LISTEN_FDNAMES=", joined, NULL);
+ if (!x)
+ return -ENOMEM;
+ our_env[n_env++] = x;
}
if (watchdog_usec > 0) {
@@ -1261,7 +1316,7 @@ static int build_environment(
}
our_env[n_env++] = NULL;
- assert(n_env <= 10);
+ assert(n_env <= 11);
*ret = our_env;
our_env = NULL;
@@ -1299,6 +1354,44 @@ static bool exec_needs_mount_namespace(
return false;
}
+static int close_remaining_fds(
+ const ExecParameters *params,
+ ExecRuntime *runtime,
+ int socket_fd,
+ int *fds, unsigned n_fds) {
+
+ unsigned n_dont_close = 0;
+ int dont_close[n_fds + 7];
+
+ assert(params);
+
+ if (params->stdin_fd >= 0)
+ dont_close[n_dont_close++] = params->stdin_fd;
+ if (params->stdout_fd >= 0)
+ dont_close[n_dont_close++] = params->stdout_fd;
+ if (params->stderr_fd >= 0)
+ dont_close[n_dont_close++] = params->stderr_fd;
+
+ if (socket_fd >= 0)
+ dont_close[n_dont_close++] = socket_fd;
+ if (n_fds > 0) {
+ memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
+ n_dont_close += n_fds;
+ }
+
+ if (params->bus_endpoint_fd >= 0)
+ dont_close[n_dont_close++] = params->bus_endpoint_fd;
+
+ if (runtime) {
+ if (runtime->netns_storage_socket[0] >= 0)
+ dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
+ if (runtime->netns_storage_socket[1] >= 0)
+ dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
+ }
+
+ return close_all_fds(dont_close, n_dont_close);
+}
+
static int exec_child(
Unit *unit,
ExecCommand *command,
@@ -1313,9 +1406,7 @@ static int exec_child(
_cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
_cleanup_free_ char *mac_selinux_context_net = NULL;
- const char *username = NULL, *home = NULL, *shell = NULL;
- unsigned n_dont_close = 0;
- int dont_close[n_fds + 4];
+ const char *username = NULL, *home = NULL, *shell = NULL, *wd;
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
int i, r;
@@ -1355,22 +1446,7 @@ static int exec_child(
log_forget_fds();
- if (socket_fd >= 0)
- dont_close[n_dont_close++] = socket_fd;
- if (n_fds > 0) {
- memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
- n_dont_close += n_fds;
- }
- if (params->bus_endpoint_fd >= 0)
- dont_close[n_dont_close++] = params->bus_endpoint_fd;
- if (runtime) {
- if (runtime->netns_storage_socket[0] >= 0)
- dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
- if (runtime->netns_storage_socket[1] >= 0)
- dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
- }
-
- r = close_all_fds(dont_close, n_dont_close);
+ r = close_remaining_fds(params, runtime, socket_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
return r;
@@ -1412,24 +1488,35 @@ static int exec_child(
}
}
+ if (context->group) {
+ const char *g = context->group;
+
+ r = get_group_creds(&g, &gid);
+ if (r < 0) {
+ *exit_status = EXIT_GROUP;
+ return r;
+ }
+ }
+
+
/* If a socket is connected to STDIN/STDOUT/STDERR, we
* must sure to drop O_NONBLOCK */
if (socket_fd >= 0)
- fd_nonblock(socket_fd, false);
+ (void) fd_nonblock(socket_fd, false);
- r = setup_input(context, socket_fd, params->apply_tty_stdin);
+ r = setup_input(context, params, socket_fd);
if (r < 0) {
*exit_status = EXIT_STDIN;
return r;
}
- r = setup_output(unit, context, STDOUT_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
+ r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid);
if (r < 0) {
*exit_status = EXIT_STDOUT;
return r;
}
- r = setup_output(unit, context, STDERR_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
+ r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid);
if (r < 0) {
*exit_status = EXIT_STDERR;
return r;
@@ -1578,25 +1665,50 @@ static int exec_child(
}
}
+ umask(context->umask);
+
if (params->apply_permissions) {
r = enforce_groups(context, username, gid);
if (r < 0) {
*exit_status = EXIT_GROUP;
return r;
}
- }
+#ifdef HAVE_SMACK
+ if (context->smack_process_label) {
+ r = mac_smack_apply_pid(0, context->smack_process_label);
+ if (r < 0) {
+ *exit_status = EXIT_SMACK_PROCESS_LABEL;
+ return r;
+ }
+ }
+#ifdef SMACK_DEFAULT_PROCESS_LABEL
+ else {
+ _cleanup_free_ char *exec_label = NULL;
- umask(context->umask);
+ r = mac_smack_read(command->path, SMACK_ATTR_EXEC, &exec_label);
+ if (r < 0 && r != -ENODATA && r != -EOPNOTSUPP) {
+ *exit_status = EXIT_SMACK_PROCESS_LABEL;
+ return r;
+ }
+ r = mac_smack_apply_pid(0, exec_label ? : SMACK_DEFAULT_PROCESS_LABEL);
+ if (r < 0) {
+ *exit_status = EXIT_SMACK_PROCESS_LABEL;
+ return r;
+ }
+ }
+#endif
+#endif
#ifdef HAVE_PAM
- if (params->apply_permissions && context->pam_name && username) {
- r = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
- if (r < 0) {
- *exit_status = EXIT_PAM;
- return r;
+ if (context->pam_name && username) {
+ r = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
+ if (r < 0) {
+ *exit_status = EXIT_PAM;
+ return r;
+ }
}
- }
#endif
+ }
if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) {
r = setup_netns(runtime->netns_storage_socket);
@@ -1650,6 +1762,13 @@ static int exec_child(
}
}
+ if (context->working_directory_home)
+ wd = home;
+ else if (context->working_directory)
+ wd = context->working_directory;
+ else
+ wd = "/";
+
if (params->apply_chroot) {
if (!needs_mount_namespace && context->root_directory)
if (chroot(context->root_directory) < 0) {
@@ -1657,21 +1776,15 @@ static int exec_child(
return -errno;
}
- if (chdir(context->working_directory ?: "/") < 0 &&
+ if (chdir(wd) < 0 &&
!context->working_directory_missing_ok) {
*exit_status = EXIT_CHDIR;
return -errno;
}
} else {
- _cleanup_free_ char *d = NULL;
-
- if (asprintf(&d, "%s/%s",
- context->root_directory ?: "",
- context->working_directory ?: "") < 0) {
- *exit_status = EXIT_MEMORY;
- return -ENOMEM;
- }
+ const char *d;
+ d = strjoina(strempty(context->root_directory), "/", strempty(wd));
if (chdir(d) < 0 &&
!context->working_directory_missing_ok) {
*exit_status = EXIT_CHDIR;
@@ -1725,33 +1838,6 @@ static int exec_child(
}
}
-#ifdef HAVE_SMACK
- if (context->smack_process_label) {
- r = mac_smack_apply_pid(0, context->smack_process_label);
- if (r < 0) {
- *exit_status = EXIT_SMACK_PROCESS_LABEL;
- return r;
- }
- }
-#ifdef SMACK_DEFAULT_PROCESS_LABEL
- else {
- _cleanup_free_ char *exec_label = NULL;
-
- r = mac_smack_read(command->path, SMACK_ATTR_EXEC, &exec_label);
- if (r < 0 && r != -ENODATA && r != -EOPNOTSUPP) {
- *exit_status = EXIT_SMACK_PROCESS_LABEL;
- return r;
- }
-
- r = mac_smack_apply_pid(0, exec_label ? : SMACK_DEFAULT_PROCESS_LABEL);
- if (r < 0) {
- *exit_status = EXIT_SMACK_PROCESS_LABEL;
- return r;
- }
- }
-#endif
-#endif
-
if (context->user) {
r = enforce_user(context, uid);
if (r < 0) {
@@ -1828,7 +1914,7 @@ static int exec_child(
#endif
}
- r = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env);
+ r = build_environment(context, n_fds, params->fd_names, params->watchdog_usec, home, username, shell, &our_env);
if (r < 0) {
*exit_status = EXIT_MEMORY;
return r;
@@ -2690,7 +2776,7 @@ int exec_command_append(ExecCommand *c, const char *path, ...) {
if (!l)
return -ENOMEM;
- r = strv_extend_strv(&c->argv, l);
+ r = strv_extend_strv(&c->argv, l, false);
if (r < 0)
return r;
diff --git a/src/core/execute.h b/src/core/execute.h
index a750246a89..f8995a4203 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -103,6 +103,7 @@ struct ExecContext {
struct rlimit *rlimit[_RLIMIT_MAX];
char *working_directory, *root_directory;
bool working_directory_missing_ok;
+ bool working_directory_home;
mode_t umask;
int oom_score_adjust;
@@ -207,21 +208,35 @@ struct ExecContext {
struct ExecParameters {
char **argv;
- int *fds; unsigned n_fds;
char **environment;
- bool apply_permissions;
- bool apply_chroot;
- bool apply_tty_stdin;
- bool confirm_spawn;
- bool selinux_context_net;
+
+ int *fds;
+ char **fd_names;
+ unsigned n_fds;
+
+ bool apply_permissions:1;
+ bool apply_chroot:1;
+ bool apply_tty_stdin:1;
+
+ bool confirm_spawn:1;
+ bool selinux_context_net:1;
+
+ bool cgroup_delegate:1;
CGroupMask cgroup_supported;
const char *cgroup_path;
- bool cgroup_delegate;
+
const char *runtime_prefix;
+
usec_t watchdog_usec;
+
int *idle_pipe;
+
char *bus_endpoint_path;
int bus_endpoint_fd;
+
+ int stdin_fd;
+ int stdout_fd;
+ int stderr_fd;
};
int exec_spawn(Unit *unit,
diff --git a/src/core/failure-action.c b/src/core/failure-action.c
index b06a7d2ae5..3412accf3e 100644
--- a/src/core/failure-action.c
+++ b/src/core/failure-action.c
@@ -32,7 +32,7 @@
static void log_and_status(Manager *m, const char *message) {
log_warning("%s", message);
manager_status_printf(m, STATUS_TYPE_EMERGENCY,
- ANSI_HIGHLIGHT_RED_ON " !! " ANSI_HIGHLIGHT_OFF,
+ ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL,
"%s", message);
}
diff --git a/src/core/job.c b/src/core/job.c
index 2a35d1e2de..558d8d2d52 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -670,13 +670,13 @@ _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_ON " OK " ANSI_HIGHLIGHT_OFF,
- [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF,
- [JOB_FAILED] = ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF,
- [JOB_DEPENDENCY] = ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF,
- [JOB_SKIPPED] = ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF,
- [JOB_ASSERT] = ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF,
- [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF,
+ [JOB_DONE] = ANSI_GREEN " OK " ANSI_NORMAL,
+ [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED " TIME " ANSI_NORMAL,
+ [JOB_FAILED] = ANSI_HIGHLIGHT_RED "FAILED" ANSI_NORMAL,
+ [JOB_DEPENDENCY] = ANSI_HIGHLIGHT_YELLOW "DEPEND" ANSI_NORMAL,
+ [JOB_SKIPPED] = ANSI_HIGHLIGHT " INFO " ANSI_NORMAL,
+ [JOB_ASSERT] = ANSI_HIGHLIGHT_YELLOW "ASSERT" ANSI_NORMAL,
+ [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW "UNSUPP" ANSI_NORMAL,
};
assert(u);
diff --git a/src/core/kill.c b/src/core/kill.c
index 2de71c6bf9..bddfa4460f 100644
--- a/src/core/kill.c
+++ b/src/core/kill.c
@@ -60,7 +60,10 @@ DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
static const char* const kill_who_table[_KILL_WHO_MAX] = {
[KILL_MAIN] = "main",
[KILL_CONTROL] = "control",
- [KILL_ALL] = "all"
+ [KILL_ALL] = "all",
+ [KILL_MAIN_FAIL] = "main-fail",
+ [KILL_CONTROL_FAIL] = "control-fail",
+ [KILL_ALL_FAIL] = "all-fail"
};
DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/core/kill.h b/src/core/kill.h
index d5f125fa41..5d97abb104 100644
--- a/src/core/kill.h
+++ b/src/core/kill.h
@@ -50,6 +50,9 @@ typedef enum KillWho {
KILL_MAIN,
KILL_CONTROL,
KILL_ALL,
+ KILL_MAIN_FAIL,
+ KILL_CONTROL_FAIL,
+ KILL_ALL_FAIL,
_KILL_WHO_MAX,
_KILL_WHO_INVALID = -1
} KillWho;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index edd55b9e45..89e624b557 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -17,7 +17,7 @@ struct ConfigPerfItem;
%%
m4_dnl Define the context options only once
m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
-`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory)
+`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context)
$1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory)
$1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user)
$1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group)
@@ -124,7 +124,10 @@ $1.StartupBlockIOWeight, config_parse_blockio_weight, 0,
$1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, offsetof($1, cgroup_context)
$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
-$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)'
+$1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting)
+$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context)
+$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)
+$1.NetClass, config_parse_netclass, 0, offsetof($1, cgroup_context)'
)m4_dnl
Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description)
Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation)
@@ -231,6 +234,8 @@ Service.FileDescriptorStoreMax, config_parse_unsigned, 0,
Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access)
Service.Sockets, config_parse_service_sockets, 0, 0
Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context)
+Service.USBFunctionDescriptors, config_parse_path, 0, offsetof(Service, usb_function_descriptors)
+Service.USBFunctionStrings, config_parse_path, 0, offsetof(Service, usb_function_strings)
EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
@@ -242,6 +247,7 @@ Socket.ListenFIFO, config_parse_socket_listen, SOCKET_FIFO
Socket.ListenNetlink, config_parse_socket_listen, SOCKET_SOCKET, 0
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.BindIPv6Only, config_parse_socket_bind, 0, 0,
Socket.Backlog, config_parse_unsigned, 0, offsetof(Socket, backlog)
Socket.BindToDevice, config_parse_socket_bindtodevice, 0, 0
@@ -255,6 +261,7 @@ Socket.SocketGroup, config_parse_unit_string_printf, 0,
Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode)
Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode)
Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept)
+Socket.Writable, config_parse_bool, 0, offsetof(Socket, writable)
Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections)
Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive)
Socket.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Socket, keep_alive_time)
@@ -280,6 +287,7 @@ Socket.MessageQueueMaxMessages, config_parse_long, 0,
Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize)
Socket.RemoveOnStop, config_parse_bool, 0, offsetof(Socket, remove_on_stop)
Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks)
+Socket.FileDescriptorName, config_parse_fdname, 0, 0
Socket.Service, config_parse_socket_service, 0, 0
m4_ifdef(`HAVE_SMACK',
`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 00cc6f7373..b1d4c6b57d 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -20,44 +20,43 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <linux/oom.h>
#include <errno.h>
-#include <string.h>
#include <fcntl.h>
-#include <sched.h>
#include <linux/fs.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-
+#include <linux/oom.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#endif
+#include <sched.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
-#include "unit.h"
-#include "strv.h"
+#include "af-list.h"
+#include "bus-error.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "cap-list.h"
+#include "cgroup.h"
#include "conf-parser.h"
-#include "load-fragment.h"
-#include "log.h"
+#include "cpu-set-util.h"
+#include "env-util.h"
+#include "errno-list.h"
#include "ioprio.h"
-#include "securebits.h"
+#include "log.h"
#include "missing.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "utf8.h"
#include "path-util.h"
-#include "env-util.h"
-#include "cgroup.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "errno-list.h"
-#include "af-list.h"
-#include "cap-list.h"
-#include "signal-util.h"
-#include "bus-internal.h"
-
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
+#include "securebits.h"
+#include "signal-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
+#include "utf8.h"
+#include "load-fragment.h"
int config_parse_warn_compat(
const char *unit,
@@ -74,15 +73,15 @@ int config_parse_warn_compat(
switch(reason) {
case DISABLED_CONFIGURATION:
- log_syntax(unit, LOG_DEBUG, filename, line, EINVAL,
+ log_syntax(unit, LOG_DEBUG, filename, line, 0,
"Support for option %s= has been disabled at compile time and it is ignored", lvalue);
break;
case DISABLED_LEGACY:
- log_syntax(unit, LOG_INFO, filename, line, EINVAL,
+ log_syntax(unit, LOG_INFO, filename, line, 0,
"Support for option %s= has been removed and it is ignored", lvalue);
break;
case DISABLED_EXPERIMENTAL:
- log_syntax(unit, LOG_INFO, filename, line, EINVAL,
+ log_syntax(unit, LOG_INFO, filename, line, 0,
"Support for option %s= has not yet been enabled and it is ignored", lvalue);
break;
};
@@ -120,18 +119,16 @@ int config_parse_unit_deps(const char *unit,
r = unit_name_printf(u, t, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
continue;
}
r = unit_add_dependency_by_name(u, d, k, NULL, true);
if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring.");
return 0;
}
@@ -166,16 +163,17 @@ int config_parse_unit_string_printf(
return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
-int config_parse_unit_strv_printf(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_unit_strv_printf(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
Unit *u = userdata;
_cleanup_free_ char *k = NULL;
@@ -187,24 +185,25 @@ int config_parse_unit_strv_printf(const char *unit,
assert(u);
r = unit_full_printf(u, rvalue, &k);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ return 0;
+ }
- return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
- k ? k : rvalue, data, userdata);
+ return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata);
}
-int config_parse_unit_path_printf(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_unit_path_printf(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
_cleanup_free_ char *k = NULL;
Unit *u = userdata;
@@ -217,7 +216,7 @@ int config_parse_unit_path_printf(const char *unit,
r = unit_full_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
return 0;
}
@@ -256,17 +255,17 @@ int config_parse_unit_path_strv_printf(
r = unit_full_printf(u, t, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", t);
return 0;
}
if (!utf8_is_valid(k)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return 0;
}
if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Symlink path %s is not absolute, ignoring: %m", k);
return 0;
}
@@ -279,7 +278,7 @@ int config_parse_unit_path_strv_printf(
k = NULL;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring.");
return 0;
}
@@ -322,12 +321,8 @@ int config_parse_socket_listen(const char *unit,
p->type = ltype;
r = unit_full_printf(UNIT(s), rvalue, &p->path);
if (r < 0) {
- p->path = strdup(rvalue);
- if (!p->path)
- return log_oom();
- else
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ return 0;
}
path_kill_slashes(p->path);
@@ -337,14 +332,14 @@ int config_parse_socket_listen(const char *unit,
p->type = SOCKET_SOCKET;
r = unit_full_printf(UNIT(s), rvalue, &k);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ return 0;
+ }
- r = socket_address_parse_netlink(&p->address, k ?: rvalue);
+ r = socket_address_parse_netlink(&p->address, k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse address value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
return 0;
}
@@ -353,14 +348,14 @@ int config_parse_socket_listen(const char *unit,
p->type = SOCKET_SOCKET;
r = unit_full_printf(UNIT(s), rvalue, &k);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
+ return 0;
+ }
- r = socket_address_parse_and_warn(&p->address, k ? k : rvalue);
+ r = socket_address_parse_and_warn(&p->address, k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse address value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
return 0;
}
@@ -374,13 +369,14 @@ int config_parse_socket_listen(const char *unit,
}
if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
- log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP,
- "Address family not supported, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue);
return 0;
}
}
p->fd = -1;
+ p->auxiliary_fds = NULL;
+ p->n_auxiliary_fds = 0;
p->socket = s;
if (s->ports) {
@@ -420,8 +416,7 @@ int config_parse_socket_bind(const char *unit,
r = parse_boolean(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
return 0;
}
@@ -453,14 +448,12 @@ int config_parse_exec_nice(const char *unit,
r = safe_atoi(rvalue, &priority);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse nice priority, ignoring: %s. ", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue);
return 0;
}
if (priority < PRIO_MIN || priority >= PRIO_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Nice priority out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Nice priority out of range, ignoring: %s", rvalue);
return 0;
}
@@ -491,14 +484,12 @@ int config_parse_exec_oom_score_adjust(const char* unit,
r = safe_atoi(rvalue, &oa);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue);
return 0;
}
if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "OOM score adjust value out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue);
return 0;
}
@@ -572,24 +563,19 @@ int config_parse_exec(
if (isempty(f)) {
/* First word is either "-" or "@" with no command. */
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Empty path in command line, ignoring: \"%s\"", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue);
return 0;
}
-
if (!string_is_safe(f)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Executable path contains special characters, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue);
return 0;
}
if (!path_is_absolute(f)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Executable path is not absolute, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue);
return 0;
}
if (endswith(f, "/")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Executable path specifies a directory, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue);
return 0;
}
@@ -656,8 +642,7 @@ int config_parse_exec(
}
if (!n || !n[0]) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
return 0;
}
@@ -741,8 +726,7 @@ int config_parse_exec_io_class(const char *unit,
x = ioprio_class_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse IO scheduling class, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue);
return 0;
}
@@ -773,8 +757,7 @@ int config_parse_exec_io_priority(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse IO priority, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue);
return 0;
}
@@ -806,8 +789,7 @@ int config_parse_exec_cpu_sched_policy(const char *unit,
x = sched_policy_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -x,
- "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
return 0;
}
@@ -840,8 +822,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
return 0;
}
@@ -850,8 +831,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit,
max = sched_get_priority_max(c->cpu_sched_policy);
if (i < min || i > max) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "CPU scheduling priority is out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue);
return 0;
}
@@ -873,50 +853,29 @@ int config_parse_exec_cpu_affinity(const char *unit,
void *userdata) {
ExecContext *c = data;
- const char *word, *state;
- size_t l;
+ _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
+ int ncpus;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
- if (isempty(rvalue)) {
- /* An empty assignment resets the CPU list */
- if (c->cpuset)
- CPU_FREE(c->cpuset);
- c->cpuset = NULL;
- return 0;
- }
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
- int r;
- unsigned cpu;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- r = safe_atou(t, &cpu);
+ ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
+ if (ncpus < 0)
+ return ncpus;
- if (!c->cpuset) {
- c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
- if (!c->cpuset)
- return log_oom();
- }
-
- if (r < 0 || cpu >= c->cpuset_ncpus) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
- return 0;
- }
+ if (c->cpuset)
+ CPU_FREE(c->cpuset);
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
+ if (ncpus == 0)
+ /* An empty assignment resets the CPU list */
+ c->cpuset = NULL;
+ else {
+ c->cpuset = cpuset;
+ cpuset = NULL;
}
- if (!isempty(state))
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ c->cpuset_ncpus = ncpus;
return 0;
}
@@ -942,8 +901,7 @@ int config_parse_exec_capabilities(const char *unit,
cap = cap_from_text(rvalue);
if (!cap) {
- log_syntax(unit, LOG_ERR, filename, line, errno,
- "Failed to parse capabilities, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capabilities, ignoring: %s", rvalue);
return 0;
}
@@ -994,14 +952,12 @@ int config_parse_exec_secure_bits(const char *unit,
else if (first_word(word, "noroot-locked"))
c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse secure bits, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse secure bits, ignoring: %s", rvalue);
return 0;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid syntax, garbage at the end, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, garbage at the end, ignoring.");
return 0;
}
@@ -1048,15 +1004,14 @@ int config_parse_bounding_set(const char *unit,
cap = capability_from_name(t);
if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse capability in bounding set, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", t);
continue;
}
sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
if (invert)
*capability_bounding_set_drop |= sum;
@@ -1094,8 +1049,7 @@ int config_parse_limit(const char *unit,
r = safe_atollu(rvalue, &u);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse resource value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
return 0;
}
}
@@ -1132,8 +1086,7 @@ int config_parse_sysv_priority(const char *unit,
r = safe_atoi(rvalue, &i);
if (r < 0 || i < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse SysV start priority, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
return 0;
}
@@ -1180,12 +1133,12 @@ int config_parse_exec_mount_flags(const char *unit,
else if (streq(t, "private"))
flags = MS_PRIVATE;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
return 0;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
c->mount_flags = flags;
return 0;
@@ -1228,8 +1181,7 @@ int config_parse_exec_selinux_context(
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0;
}
@@ -1277,8 +1229,7 @@ int config_parse_exec_apparmor_profile(
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0;
}
@@ -1326,8 +1277,7 @@ int config_parse_exec_smack_process_label(
r = unit_name_printf(u, rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
return 0;
}
@@ -1368,23 +1318,18 @@ int config_parse_timer(const char *unit,
b = timer_base_from_string(lvalue);
if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -b,
- "Failed to parse timer base, ignoring: %s", lvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue);
return 0;
}
if (b == TIMER_CALENDAR) {
if (calendar_spec_from_string(rvalue, &c) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse calendar specification, ignoring: %s",
- rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", rvalue);
return 0;
}
} else {
if (parse_sec(rvalue, &u) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse timer value, ignoring: %s",
- rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", rvalue);
return 0;
}
}
@@ -1427,33 +1372,30 @@ int config_parse_trigger_unit(
assert(data);
if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Multiple units to trigger specified, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue);
return 0;
}
r = unit_name_printf(u, rvalue, &p);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
+ return 0;
+ }
- type = unit_name_to_type(p ?: rvalue);
+ type = unit_name_to_type(p);
if (type < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit type not valid, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
return 0;
}
if (type == u->type) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trigger cannot be of same type, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
return 0;
}
- r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
+ r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
return 0;
}
@@ -1490,25 +1432,18 @@ int config_parse_path_spec(const char *unit,
b = path_type_from_string(lvalue);
if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse path type, ignoring: %s", lvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue);
return 0;
}
r = unit_full_printf(UNIT(p), rvalue, &k);
if (r < 0) {
- k = strdup(rvalue);
- if (!k)
- return log_oom();
- else
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s. Ignoring.",
- rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
+ return 0;
}
if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Path is not absolute, ignoring: %s", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k);
return 0;
}
@@ -1540,10 +1475,10 @@ int config_parse_socket_service(
void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *p = NULL;
Socket *s = data;
- int r;
Unit *x;
- _cleanup_free_ char *p = NULL;
+ int r;
assert(filename);
assert(lvalue);
@@ -1557,13 +1492,13 @@ int config_parse_socket_service(
}
if (!endswith(p, ".service")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
return 0;
}
r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
return 0;
}
@@ -1572,6 +1507,50 @@ int config_parse_socket_service(
return 0;
}
+int config_parse_fdname(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *p = NULL;
+ Socket *s = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ s->fdname = mfree(s->fdname);
+ return 0;
+ }
+
+ r = unit_name_printf(UNIT(s), rvalue, &p);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (!fdname_is_valid(p)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
+ return 0;
+ }
+
+ free(s->fdname);
+ s->fdname = p;
+ p = NULL;
+
+ return 0;
+}
+
int config_parse_service_sockets(
const char *unit,
const char *filename,
@@ -1608,7 +1587,7 @@ int config_parse_service_sockets(
}
if (!endswith(k, ".socket")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k);
continue;
}
@@ -1621,7 +1600,7 @@ int config_parse_service_sockets(
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -1654,7 +1633,7 @@ int config_parse_bus_name(
}
if (!service_name_is_valid(k)) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k);
return 0;
}
@@ -1719,21 +1698,18 @@ int config_parse_busname_service(
r = unit_name_printf(UNIT(n), rvalue, &p);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
return 0;
}
if (!endswith(p, ".service")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit must be of type service, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue);
return 0;
}
r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
return 0;
}
@@ -1783,8 +1759,7 @@ int config_parse_bus_policy(
access_str = strpbrk(id_str, WHITESPACE);
if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid busname policy value '%s'", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue);
return 0;
}
@@ -1794,8 +1769,7 @@ int config_parse_bus_policy(
p->access = bus_policy_access_from_string(access_str);
if (p->access < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid busname policy access type '%s'", access_str);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str);
return 0;
}
@@ -1837,8 +1811,7 @@ int config_parse_bus_endpoint_policy(
access_str = strpbrk(name, WHITESPACE);
if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid endpoint policy value '%s'", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy value '%s'", rvalue);
return 0;
}
@@ -1849,21 +1822,83 @@ int config_parse_bus_endpoint_policy(
access = bus_policy_access_from_string(access_str);
if (access <= _BUS_POLICY_ACCESS_INVALID ||
access >= _BUS_POLICY_ACCESS_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid endpoint policy access type '%s'", access_str);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy access type '%s'", access_str);
return 0;
}
if (!c->bus_endpoint) {
r = bus_endpoint_new(&c->bus_endpoint);
-
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to create bus endpoint object: %m");
}
return bus_endpoint_add_policy(c->bus_endpoint, name, access);
}
+int config_parse_working_directory(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ ExecContext *c = data;
+ Unit *u = userdata;
+ bool missing_ok;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(c);
+ assert(u);
+
+ if (rvalue[0] == '-') {
+ missing_ok = true;
+ rvalue++;
+ } else
+ missing_ok = false;
+
+ if (streq(rvalue, "~")) {
+ c->working_directory_home = true;
+ c->working_directory = mfree(c->working_directory);
+ } else {
+ _cleanup_free_ char *k = NULL;
+
+ r = unit_full_printf(u, rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue);
+ return 0;
+ }
+
+ path_kill_slashes(k);
+
+ if (!utf8_is_valid(k)) {
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+ return 0;
+ }
+
+ if (!path_is_absolute(k)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue);
+ return 0;
+ }
+
+ free(c->working_directory);
+ c->working_directory = k;
+ k = NULL;
+
+ c->working_directory_home = false;
+ }
+
+ c->working_directory_missing_ok = missing_ok;
+ return 0;
+}
+
int config_parse_unit_env_file(const char *unit,
const char *filename,
unsigned line,
@@ -1878,7 +1913,6 @@ int config_parse_unit_env_file(const char *unit,
char ***env = data;
Unit *u = userdata;
_cleanup_free_ char *n = NULL;
- const char *s;
int r;
assert(filename);
@@ -1893,18 +1927,17 @@ int config_parse_unit_env_file(const char *unit,
}
r = unit_full_printf(u, rvalue, &n);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
- s = n ?: rvalue;
- if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Path '%s' is not absolute, ignoring.", s);
+ if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
return 0;
}
- r = strv_extend(env, s);
+ r = strv_extend(env, n);
if (r < 0)
return log_oom();
@@ -1942,14 +1975,17 @@ int config_parse_environ(const char *unit,
if (u) {
r = unit_full_printf(u, rvalue, &k);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
}
- if (!k)
+ if (!k) {
k = strdup(rvalue);
- if (!k)
- return log_oom();
+ if (!k)
+ return log_oom();
+ }
FOREACH_WORD_QUOTED(word, l, k, state) {
_cleanup_free_ char *n = NULL;
@@ -1962,7 +1998,7 @@ int config_parse_environ(const char *unit,
}
if (!env_assignment_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid environment assignment, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid environment assignment, ignoring: %s", rvalue);
continue;
}
@@ -1974,8 +2010,7 @@ int config_parse_environ(const char *unit,
*env = x;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2000,8 +2035,7 @@ int config_parse_ip_tos(const char *unit,
x = ip_tos_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse IP TOS value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
return 0;
}
@@ -2049,12 +2083,12 @@ int config_parse_unit_condition_path(
r = unit_full_printf(u, rvalue, &p);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
return 0;
}
if (!path_is_absolute(p)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p);
return 0;
}
@@ -2106,7 +2140,7 @@ int config_parse_unit_condition_string(
r = unit_full_printf(u, rvalue, &s);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
return 0;
}
@@ -2155,7 +2189,7 @@ int config_parse_unit_condition_null(
b = parse_boolean(rvalue);
if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
return 0;
}
@@ -2203,20 +2237,18 @@ int config_parse_unit_requires_mounts_for(
return log_oom();
if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
continue;
}
r = unit_require_mounts_for(u, n);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add required mount for, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount for, ignoring: %s", rvalue);
continue;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2257,8 +2289,7 @@ int config_parse_documentation(const char *unit,
if (documentation_url_is_valid(*a))
*(b++) = *a;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid URL, ignoring: %s", *a);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a);
free(*a);
}
}
@@ -2353,8 +2384,7 @@ int config_parse_syscall_filter(
id = seccomp_syscall_resolve_name(t);
if (id < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse system call, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
continue;
}
@@ -2371,8 +2401,7 @@ int config_parse_syscall_filter(
set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
/* Turn on NNP, but only if it wasn't configured explicitly
* before, and only if we are in user mode. */
@@ -2418,8 +2447,7 @@ int config_parse_syscall_archs(
r = seccomp_arch_from_string(t, &a);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse system call architecture, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t);
continue;
}
@@ -2430,8 +2458,7 @@ int config_parse_syscall_archs(
return log_oom();
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2463,8 +2490,7 @@ int config_parse_syscall_errno(
e = errno_from_name(rvalue);
if (e < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse error number, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue);
return 0;
}
@@ -2524,8 +2550,7 @@ int config_parse_address_families(
af = af_from_name(t);
if (af <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse address family, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse address family, ignoring: %s", t);
continue;
}
@@ -2542,8 +2567,7 @@ int config_parse_address_families(
set_remove(c->address_families, INT_TO_PTR(af));
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -2605,26 +2629,19 @@ int config_parse_cpu_shares(
void *data,
void *userdata) {
- unsigned long *shares = data, lu;
+ uint64_t *shares = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- if (isempty(rvalue)) {
- *shares = (unsigned long) -1;
- return 0;
- }
-
- r = safe_atolu(rvalue, &lu);
- if (r < 0 || lu <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU shares '%s' invalid. Ignoring.", rvalue);
+ r = cg_cpu_shares_parse(rvalue, shares);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
return 0;
}
- *shares = lu;
return 0;
}
@@ -2653,15 +2670,12 @@ int config_parse_cpu_quota(
}
if (!endswith(rvalue, "%")) {
-
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
return 0;
}
if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU quota '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue);
return 0;
}
@@ -2686,15 +2700,14 @@ int config_parse_memory_limit(
uint64_t bytes;
int r;
- if (isempty(rvalue)) {
+ if (isempty(rvalue) || streq(rvalue, "infinity")) {
c->memory_limit = (uint64_t) -1;
return 0;
}
r = parse_size(rvalue, 1024, &bytes);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Memory limit '%s' invalid. Ignoring.", rvalue);
+ if (r < 0 || bytes < 1) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
return 0;
}
@@ -2702,6 +2715,36 @@ int config_parse_memory_limit(
return 0;
}
+int config_parse_tasks_max(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ CGroupContext *c = data;
+ uint64_t u;
+ int r;
+
+ if (isempty(rvalue) || streq(rvalue, "infinity")) {
+ c->tasks_max = (uint64_t) -1;
+ return 0;
+ }
+
+ r = safe_atou64(rvalue, &u);
+ if (r < 0 || u < 1) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ return 0;
+}
+
int config_parse_device_allow(
const char *unit,
const char *filename,
@@ -2735,8 +2778,7 @@ int config_parse_device_allow(
if (!startswith(path, "/dev/") &&
!startswith(path, "block-") &&
!startswith(path, "char-")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
@@ -2745,8 +2787,7 @@ int config_parse_device_allow(
m = "rwm";
if (!in_charset(m, "rwm")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device rights '%s'. Ignoring.", m);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m);
return 0;
}
@@ -2776,26 +2817,19 @@ int config_parse_blockio_weight(
void *data,
void *userdata) {
- unsigned long *weight = data, lu;
+ uint64_t *weight = data;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
- if (isempty(rvalue)) {
- *weight = (unsigned long) -1;
- return 0;
- }
-
- r = safe_atolu(rvalue, &lu);
- if (r < 0 || lu < 10 || lu > 1000) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Block IO weight '%s' invalid. Ignoring.", rvalue);
+ r = cg_blkio_weight_parse(rvalue, weight);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
return 0;
}
- *weight = lu;
return 0;
}
@@ -2814,8 +2848,8 @@ int config_parse_blockio_device_weight(
_cleanup_free_ char *path = NULL;
CGroupBlockIODeviceWeight *w;
CGroupContext *c = data;
- unsigned long lu;
const char *weight;
+ uint64_t u;
size_t n;
int r;
@@ -2832,9 +2866,10 @@ int config_parse_blockio_device_weight(
n = strcspn(rvalue, WHITESPACE);
weight = rvalue + n;
- if (!*weight) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Expected block device and device weight. Ignoring.");
+ weight += strspn(weight, WHITESPACE);
+
+ if (isempty(weight)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
return 0;
}
@@ -2843,19 +2878,18 @@ int config_parse_blockio_device_weight(
return log_oom();
if (!path_startswith(path, "/dev")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
- weight += strspn(weight, WHITESPACE);
- r = safe_atolu(weight, &lu);
- if (r < 0 || lu < 10 || lu > 1000) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Block IO weight '%s' invalid. Ignoring.", rvalue);
+ r = cg_blkio_weight_parse(weight, &u);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
return 0;
}
+ assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
+
w = new0(CGroupBlockIODeviceWeight, 1);
if (!w)
return log_oom();
@@ -2863,7 +2897,7 @@ int config_parse_blockio_device_weight(
w->path = path;
path = NULL;
- w->weight = lu;
+ w->weight = u;
LIST_PREPEND(device_weights, c->blockio_device_weights, w);
return 0;
@@ -2911,8 +2945,7 @@ int config_parse_blockio_bandwidth(
bandwidth += strspn(bandwidth, WHITESPACE);
if (!*bandwidth) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Expected space separated pair of device node and bandwidth. Ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
return 0;
}
@@ -2921,15 +2954,13 @@ int config_parse_blockio_bandwidth(
return log_oom();
if (!path_startswith(path, "/dev")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
return 0;
}
r = parse_size(bandwidth, 1000, &bytes);
if (r < 0 || bytes <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
return 0;
}
@@ -2947,6 +2978,47 @@ int config_parse_blockio_bandwidth(
return 0;
}
+int config_parse_netclass(
+ 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) {
+
+ CGroupContext *c = data;
+ unsigned v;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (streq(rvalue, "auto")) {
+ c->netclass_type = CGROUP_NETCLASS_TYPE_AUTO;
+ return 0;
+ }
+
+ r = safe_atou32(rvalue, &v);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Netclass '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ if (v > CGROUP_NETCLASS_FIXED_MAX)
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Fixed netclass %" PRIu32 " out of allowed range (0-%d). Applying anyway.", v, (uint32_t) CGROUP_NETCLASS_FIXED_MAX);
+
+ c->netclass_id = v;
+ c->netclass_type = CGROUP_NETCLASS_TYPE_FIXED;
+
+ return 0;
+}
+
DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode");
int config_parse_job_mode_isolate(
@@ -2970,8 +3042,7 @@ int config_parse_job_mode_isolate(
r = parse_boolean(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse boolean, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue);
return 0;
}
@@ -2992,6 +3063,7 @@ int config_parse_runtime_directory(
void *userdata) {
char***rt = data;
+ Unit *u = userdata;
const char *word, *state;
size_t l;
int r;
@@ -3008,15 +3080,20 @@ int config_parse_runtime_directory(
}
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
+ _cleanup_free_ char *t = NULL, *n = NULL;
- n = strndup(word, l);
- if (!n)
+ t = strndup(word, l);
+ if (!t)
return log_oom();
+ r = unit_name_printf(u, t, &n);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
+ continue;
+ }
+
if (!filename_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Runtime directory is not valid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue);
continue;
}
@@ -3027,8 +3104,7 @@ int config_parse_runtime_directory(
n = NULL;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -3075,15 +3151,13 @@ int config_parse_set_status(
val = signal_from_string_try_harder(temp);
if (val <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, -val,
- "Failed to parse value, ignoring: %s", word);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word);
continue;
}
set = &status_set->signal;
} else {
if (val < 0 || val > 255) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Value %d is outside range 0-255, ignoring", val);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val);
continue;
}
set = &status_set->status;
@@ -3095,14 +3169,12 @@ int config_parse_set_status(
r = set_put(*set, INT_TO_PTR(val));
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Unable to store: %s", word);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word);
return r;
}
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -3144,14 +3216,13 @@ int config_parse_namespace_path_strv(
return log_oom();
if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
continue;
}
offset = n[0] == '-';
if (!path_is_absolute(n + offset)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Not an absolute path, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
continue;
}
@@ -3164,8 +3235,7 @@ int config_parse_namespace_path_strv(
n = NULL;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -3192,8 +3262,7 @@ int config_parse_no_new_privileges(
k = parse_boolean(rvalue);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -k,
- "Failed to parse boolean value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
return 0;
}
@@ -3236,8 +3305,7 @@ int config_parse_protect_home(
h = protect_home_from_string(rvalue);
if (h < 0){
- log_syntax(unit, LOG_ERR, filename, line, -h,
- "Failed to parse protect home value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
return 0;
}
@@ -3280,8 +3348,7 @@ int config_parse_protect_system(
s = protect_system_from_string(rvalue);
if (s < 0){
- log_syntax(unit, LOG_ERR, filename, line, -s,
- "Failed to parse protect system value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 1d128716c4..8661cbfedc 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -84,11 +84,13 @@ int config_parse_environ(const char *unit, const char *filename, unsigned line,
int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_tasks_max(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_device_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_device_allow(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_blockio_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_blockio_device_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_blockio_bandwidth(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_netclass(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_job_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_job_mode_isolate(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_selinux_context(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);
@@ -104,6 +106,8 @@ int config_parse_protect_home(const char* unit, const char *filename, unsigned l
int config_parse_protect_system(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bus_name(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_fdname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index 8f682c6d10..363ffaaf05 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -19,24 +19,25 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <stdio.h>
#include <errno.h>
-#include <string.h>
#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
#include <sys/mount.h>
+#include <unistd.h>
-#include "systemd/sd-id128.h"
+#include "sd-id128.h"
-#include "machine-id-setup.h"
+#include "fileio.h"
+#include "log.h"
#include "macro.h"
-#include "util.h"
#include "mkdir.h"
-#include "log.h"
-#include "virt.h"
-#include "fileio.h"
#include "path-util.h"
#include "process-util.h"
+#include "util.h"
+#include "virt.h"
+#include "machine-id-setup.h"
static int shorten_uuid(char destination[34], const char source[36]) {
unsigned i, j;
diff --git a/src/core/main.c b/src/core/main.c
index c9657505c3..87b3af92bc 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -19,63 +19,64 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
+#include <fcntl.h>
#include <getopt.h>
#include <signal.h>
-#include <fcntl.h>
-#include <sys/prctl.h>
+#include <stdio.h>
+#include <string.h>
#include <sys/mount.h>
-
-#ifdef HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
-#endif
+#include <sys/prctl.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <unistd.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
#endif
+#ifdef HAVE_VALGRIND_VALGRIND_H
+#include <valgrind/valgrind.h>
+#endif
#include "sd-daemon.h"
#include "sd-bus.h"
-#include "log.h"
-#include "fdset.h"
-#include "special.h"
-#include "conf-parser.h"
-#include "missing.h"
-#include "pager.h"
-#include "build.h"
-#include "strv.h"
-#include "def.h"
-#include "virt.h"
+
#include "architecture.h"
-#include "watchdog.h"
-#include "switch-root.h"
+#include "build.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "capability.h"
-#include "killall.h"
-#include "env-util.h"
#include "clock-util.h"
+#include "conf-parser.h"
+#include "cpu-set-util.h"
+#include "dbus-manager.h"
+#include "def.h"
+#include "env-util.h"
+#include "fdset.h"
#include "fileio.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "selinux-util.h"
#include "formats-util.h"
-#include "process-util.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-#include "manager.h"
-#include "dbus-manager.h"
+#include "hostname-setup.h"
+#include "ima-setup.h"
+#include "killall.h"
+#include "kmod-setup.h"
#include "load-fragment.h"
-
-#include "mount-setup.h"
+#include "log.h"
#include "loopback-setup.h"
-#include "hostname-setup.h"
#include "machine-id-setup.h"
+#include "manager.h"
+#include "missing.h"
+#include "mount-setup.h"
+#include "pager.h"
+#include "process-util.h"
#include "selinux-setup.h"
-#include "ima-setup.h"
+#include "selinux-util.h"
+#include "signal-util.h"
#include "smack-setup.h"
-#include "kmod-setup.h"
+#include "special.h"
+#include "strv.h"
+#include "switch-root.h"
+#include "terminal-util.h"
+#include "virt.h"
+#include "watchdog.h"
static enum {
ACTION_RUN,
@@ -88,8 +89,9 @@ static enum {
static char *arg_default_unit = NULL;
static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
static bool arg_dump_core = true;
-static bool arg_crash_shell = false;
static int arg_crash_chvt = -1;
+static bool arg_crash_shell = false;
+static bool arg_crash_reboot = false;
static bool arg_confirm_spawn = false;
static ShowStatus arg_show_status = _SHOW_STATUS_UNSET;
static bool arg_switched_root = false;
@@ -114,8 +116,7 @@ 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 void nop_handler(int sig) {}
+static bool arg_default_tasks_accounting = false;
static void pager_open_if_enabled(void) {
@@ -125,49 +126,66 @@ static void pager_open_if_enabled(void) {
pager_open(false);
}
+noreturn static void freeze_or_reboot(void) {
+
+ if (arg_crash_reboot) {
+ log_notice("Rebooting in 10s...");
+ (void) sleep(10);
+
+ log_notice("Rebooting now...");
+ (void) reboot(RB_AUTOBOOT);
+ log_emergency_errno(errno, "Failed to reboot: %m");
+ }
+
+ log_emergency("Freezing execution.");
+ freeze();
+}
+
noreturn static void crash(int sig) {
+ struct sigaction sa;
+ pid_t pid;
if (getpid() != 1)
/* Pass this on immediately, if this is not PID 1 */
- raise(sig);
+ (void) raise(sig);
else if (!arg_dump_core)
log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
else {
- struct sigaction sa = {
- .sa_handler = nop_handler,
+ sa = (struct sigaction) {
+ .sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP|SA_RESTART,
};
- pid_t pid;
/* We want to wait for the core process, hence let's enable SIGCHLD */
- sigaction(SIGCHLD, &sa, NULL);
+ (void) sigaction(SIGCHLD, &sa, NULL);
pid = raw_clone(SIGCHLD, NULL);
if (pid < 0)
log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
-
else if (pid == 0) {
- struct rlimit rl = {};
+ struct rlimit rl = {
+ .rlim_cur = RLIM_INFINITY,
+ .rlim_max = RLIM_INFINITY,
+ };
/* Enable default signal handler for core dump */
- zero(sa);
- sa.sa_handler = SIG_DFL;
- sigaction(sig, &sa, NULL);
+ sa = (struct sigaction) {
+ .sa_handler = SIG_DFL,
+ };
+ (void) sigaction(sig, &sa, NULL);
/* Don't limit the core dump size */
- rl.rlim_cur = RLIM_INFINITY;
- rl.rlim_max = RLIM_INFINITY;
- setrlimit(RLIMIT_CORE, &rl);
+ (void) setrlimit(RLIMIT_CORE, &rl);
/* Just to be sure... */
(void) chdir("/");
/* Raise the signal again */
pid = raw_getpid();
- kill(pid, sig); /* raise() would kill the parent */
+ (void) kill(pid, sig); /* raise() would kill the parent */
assert_not_reached("We shouldn't be here...");
- _exit(1);
+ _exit(EXIT_FAILURE);
} else {
siginfo_t status;
int r;
@@ -189,37 +207,38 @@ noreturn static void crash(int sig) {
}
}
- if (arg_crash_chvt)
- chvt(arg_crash_chvt);
+ if (arg_crash_chvt >= 0)
+ (void) chvt(arg_crash_chvt);
- if (arg_crash_shell) {
- struct sigaction sa = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
- };
- pid_t pid;
+ sa = (struct sigaction) {
+ .sa_handler = SIG_IGN,
+ .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
+ };
- log_info("Executing crash shell in 10s...");
- sleep(10);
+ /* Let the kernel reap children for us */
+ (void) sigaction(SIGCHLD, &sa, NULL);
- /* Let the kernel reap children for us */
- assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
+ if (arg_crash_shell) {
+ log_notice("Executing crash shell in 10s...");
+ (void) sleep(10);
pid = raw_clone(SIGCHLD, NULL);
if (pid < 0)
log_emergency_errno(errno, "Failed to fork off crash shell: %m");
else if (pid == 0) {
- make_console_stdio();
- execle("/bin/sh", "/bin/sh", NULL, environ);
+ (void) setsid();
+ (void) make_console_stdio();
+ (void) execle("/bin/sh", "/bin/sh", NULL, environ);
log_emergency_errno(errno, "execle() failed: %m");
- _exit(1);
- } else
- log_info("Successfully spawned crash shell as PID "PID_FMT".", pid);
+ _exit(EXIT_FAILURE);
+ } else {
+ log_info("Spawned crash shell as PID "PID_FMT".", pid);
+ (void) wait_for_terminate(pid, NULL);
+ }
}
- log_emergency("Freezing execution.");
- freeze();
+ freeze_or_reboot();
}
static void install_crash_handler(void) {
@@ -253,17 +272,20 @@ static int console_setup(void) {
return 0;
}
-static int set_default_unit(const char *u) {
- char *c;
+static int parse_crash_chvt(const char *value) {
+ int b;
- assert(u);
+ if (safe_atoi(value, &arg_crash_chvt) >= 0)
+ return 0;
- c = strdup(u);
- if (!c)
- return -ENOMEM;
+ b = parse_boolean(value);
+ if (b < 0)
+ return b;
- free(arg_default_unit);
- arg_default_unit = c;
+ if (b > 0)
+ arg_crash_chvt = 0; /* switch to where kmsg goes */
+ else
+ arg_crash_chvt = -1; /* turn off switching */
return 0;
}
@@ -291,12 +313,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
if (streq(key, "systemd.unit") && value) {
if (!in_initrd())
- return set_default_unit(value);
+ return free_and_strdup(&arg_default_unit, value);
} else if (streq(key, "rd.systemd.unit") && value) {
if (in_initrd())
- return set_default_unit(value);
+ return free_and_strdup(&arg_default_unit, value);
} else if (streq(key, "systemd.dump_core") && value) {
@@ -306,6 +328,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
else
arg_dump_core = r;
+ } else if (streq(key, "systemd.crash_chvt") && value) {
+
+ if (parse_crash_chvt(value) < 0)
+ log_warning("Failed to parse crash chvt switch %s. Ignoring.", value);
+
} else if (streq(key, "systemd.crash_shell") && value) {
r = parse_boolean(value);
@@ -314,12 +341,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
else
arg_crash_shell = r;
- } else if (streq(key, "systemd.crash_chvt") && value) {
+ } else if (streq(key, "systemd.crash_reboot") && value) {
- if (safe_atoi(value, &r) < 0)
- log_warning("Failed to parse crash chvt switch %s. Ignoring.", value);
+ r = parse_boolean(value);
+ if (r < 0)
+ log_warning("Failed to parse crash reboot switch %s. Ignoring.", value);
else
- arg_crash_chvt = r;
+ arg_crash_reboot = r;
} else if (streq(key, "systemd.confirm_spawn") && value) {
@@ -383,7 +411,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
/* SysV compatibility */
for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
if (streq(key, rlmap[i]))
- return set_default_unit(rlmap[i+1]);
+ return free_and_strdup(&arg_default_unit, rlmap[i+1]);
}
return 0;
@@ -409,9 +437,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
\
r = func(rvalue); \
if (r < 0) \
- log_syntax(unit, LOG_ERR, filename, line, -r, \
- "Invalid " descr "'%s': %s", \
- rvalue, strerror(-r)); \
+ log_syntax(unit, LOG_ERR, filename, line, r, \
+ "Invalid " descr "'%s': %m", \
+ rvalue); \
\
return 0; \
}
@@ -433,48 +461,15 @@ static int config_parse_cpu_affinity2(
void *data,
void *userdata) {
- const char *whole_rvalue = rvalue;
_cleanup_cpu_free_ cpu_set_t *c = NULL;
- unsigned ncpus = 0;
+ int ncpus;
- assert(filename);
- assert(lvalue);
- assert(rvalue);
+ ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue);
+ if (ncpus < 0)
+ return ncpus;
- for (;;) {
- _cleanup_free_ char *word = NULL;
- unsigned cpu;
- int r;
-
- r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
- return r;
- }
- if (r == 0)
- break;
-
- r = safe_atou(word, &cpu);
-
- if (!c)
- if (!(c = cpu_set_malloc(&ncpus)))
- return log_oom();
-
- if (r < 0 || cpu >= ncpus) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse CPU affinity '%s'", rvalue);
- return -EBADMSG;
- }
-
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
- }
- if (!isempty(rvalue))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- if (c)
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
- log_warning("Failed to set CPU affinity: %m");
+ if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
+ log_warning("Failed to set CPU affinity: %m");
return 0;
}
@@ -501,29 +496,38 @@ static int config_parse_show_status(
k = parse_show_status(rvalue, b);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -k,
- "Failed to parse show status setting, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse show status setting, ignoring: %s", rvalue);
return 0;
}
return 0;
}
-static void strv_free_free(char ***l) {
- char ***i;
+static int config_parse_crash_chvt(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
- if (!l)
- return;
+ int r;
- for (i = l; *i; i++)
- strv_free(*i);
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
- free(l);
-}
+ r = parse_crash_chvt(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue);
+ return 0;
+ }
-static void free_join_controllers(void) {
- strv_free_free(arg_join_controllers);
- arg_join_controllers = NULL;
+ return 0;
}
static int config_parse_join_controllers(const char *unit,
@@ -544,7 +548,7 @@ static int config_parse_join_controllers(const char *unit,
assert(lvalue);
assert(rvalue);
- free_join_controllers();
+ arg_join_controllers = strv_free_free(arg_join_controllers);
for (;;) {
_cleanup_free_ char *word = NULL;
@@ -561,7 +565,7 @@ static int config_parse_join_controllers(const char *unit,
l = strv_split(word, ",");
if (!l)
- log_oom();
+ return log_oom();
strv_uniq(l);
if (strv_length(l) <= 1) {
@@ -595,7 +599,7 @@ static int config_parse_join_controllers(const char *unit,
for (a = arg_join_controllers; *a; a++) {
if (strv_overlap(*a, l)) {
- if (strv_extend_strv(&l, *a) < 0) {
+ if (strv_extend_strv(&l, *a, false) < 0) {
strv_free(l);
strv_free_free(t);
return log_oom();
@@ -622,8 +626,7 @@ static int config_parse_join_controllers(const char *unit,
}
}
if (!isempty(rvalue))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -636,9 +639,11 @@ static int parse_config_file(void) {
{ "Manager", "LogColor", config_parse_color, 0, NULL },
{ "Manager", "LogLocation", config_parse_location, 0, NULL },
{ "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core },
+ { "Manager", "CrashChVT", /* legacy */ config_parse_crash_chvt, 0, NULL },
+ { "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, NULL },
{ "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell },
+ { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot },
{ "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status },
- { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt },
{ "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL },
{ "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
{ "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
@@ -676,6 +681,7 @@ static int parse_config_file(void) {
{ "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 },
{}
};
@@ -704,6 +710,7 @@ static void manager_set_defaults(Manager *m) {
m->default_cpu_accounting = arg_default_cpu_accounting;
m->default_blockio_accounting = arg_default_blockio_accounting;
m->default_memory_accounting = arg_default_memory_accounting;
+ m->default_tasks_accounting = arg_default_tasks_accounting;
manager_set_default_rlimits(m, arg_default_rlimit);
manager_environment_add(m, NULL, arg_default_environment);
@@ -724,7 +731,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION,
ARG_DUMP_CONFIGURATION_ITEMS,
ARG_DUMP_CORE,
+ ARG_CRASH_CHVT,
ARG_CRASH_SHELL,
+ ARG_CRASH_REBOOT,
ARG_CONFIRM_SPAWN,
ARG_SHOW_STATUS,
ARG_DESERIALIZE,
@@ -747,7 +756,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS },
{ "dump-core", optional_argument, NULL, ARG_DUMP_CORE },
+ { "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT },
{ "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL },
+ { "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT },
{ "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN },
{ "show-status", optional_argument, NULL, ARG_SHOW_STATUS },
{ "deserialize", required_argument, NULL, ARG_DESERIALIZE },
@@ -832,7 +843,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_UNIT:
- r = set_default_unit(optarg);
+ r = free_and_strdup(&arg_default_unit, optarg);
if (r < 0)
return log_error_errno(r, "Failed to set default unit %s: %m", optarg);
@@ -865,21 +876,42 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_DUMP_CORE:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse dump core boolean %s.", optarg);
- return r;
+ if (!optarg)
+ arg_dump_core = true;
+ else {
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse dump core boolean: %s", optarg);
+ arg_dump_core = r;
}
- arg_dump_core = r;
+ break;
+
+ case ARG_CRASH_CHVT:
+ r = parse_crash_chvt(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse crash virtual terminal index: %s", optarg);
break;
case ARG_CRASH_SHELL:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse crash shell boolean %s.", optarg);
- return r;
+ if (!optarg)
+ arg_crash_shell = true;
+ else {
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg);
+ arg_crash_shell = r;
+ }
+ break;
+
+ case ARG_CRASH_REBOOT:
+ if (!optarg)
+ arg_crash_reboot = true;
+ else {
+ r = parse_boolean(optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg);
+ arg_crash_reboot = r;
}
- arg_crash_shell = r;
break;
case ARG_CONFIRM_SPAWN:
@@ -909,17 +941,16 @@ static int parse_argv(int argc, char *argv[]) {
r = safe_atoi(optarg, &fd);
if (r < 0 || fd < 0) {
log_error("Failed to parse deserialize option %s.", optarg);
- return r < 0 ? r : -EINVAL;
+ return -EINVAL;
}
- fd_cloexec(fd, true);
+ (void) fd_cloexec(fd, true);
f = fdopen(fd, "r");
if (!f)
return log_error_errno(errno, "Failed to open serialization fd: %m");
safe_fclose(arg_serialization);
-
arg_serialization = f;
break;
@@ -979,14 +1010,16 @@ static int help(void) {
" --unit=UNIT Set default unit\n"
" --system Run a system instance, even if PID != 1\n"
" --user Run a user instance\n"
- " --dump-core[=0|1] Dump core on crash\n"
- " --crash-shell[=0|1] Run shell on crash\n"
- " --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n"
- " --show-status[=0|1] Show status updates on the console during bootup\n"
+ " --dump-core[=BOOL] Dump core on crash\n"
+ " --crash-vt=NR Change to specified VT on crash\n"
+ " --crash-reboot[=BOOL] Reboot on crash\n"
+ " --crash-shell[=BOOL] Run shell on crash\n"
+ " --confirm-spawn[=BOOL] Ask for confirmation when spawning processes\n"
+ " --show-status[=BOOL] Show status updates on the console during bootup\n"
" --log-target=TARGET Set log target (console, journal, kmsg, journal-or-kmsg, null)\n"
" --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n"
- " --log-color[=0|1] Highlight important log messages\n"
- " --log-location[=0|1] Include code location in log messages\n"
+ " --log-color[=BOOL] Highlight important log messages\n"
+ " --log-location[=BOOL] Include code location in log messages\n"
" --default-standard-output= Set default standard output for services\n"
" --default-standard-error= Set default standard error output for services\n",
program_invocation_short_name);
@@ -994,16 +1027,9 @@ static int help(void) {
return 0;
}
-static int version(void) {
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
-
- return 0;
-}
-
static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching_root) {
- FILE *f = NULL;
- FDSet *fds = NULL;
+ _cleanup_fdset_free_ FDSet *fds = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
int r;
assert(m);
@@ -1011,56 +1037,39 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching
assert(_fds);
r = manager_open_serialization(m, &f);
- if (r < 0) {
- log_error_errno(r, "Failed to create serialization file: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create serialization file: %m");
/* Make sure nothing is really destructed when we shut down */
m->n_reloading ++;
bus_manager_send_reloading(m, true);
fds = fdset_new();
- if (!fds) {
- r = -ENOMEM;
- log_error_errno(r, "Failed to allocate fd set: %m");
- goto fail;
- }
+ if (!fds)
+ return log_oom();
r = manager_serialize(m, f, fds, switching_root);
- if (r < 0) {
- log_error_errno(r, "Failed to serialize state: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to serialize state: %m");
- if (fseeko(f, 0, SEEK_SET) < 0) {
- log_error_errno(errno, "Failed to rewind serialization fd: %m");
- goto fail;
- }
+ if (fseeko(f, 0, SEEK_SET) == (off_t) -1)
+ return log_error_errno(errno, "Failed to rewind serialization fd: %m");
r = fd_cloexec(fileno(f), false);
- if (r < 0) {
- log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m");
r = fdset_cloexec(fds, false);
- if (r < 0) {
- log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m");
- goto fail;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m");
*_f = f;
*_fds = fds;
- return 0;
-
-fail:
- fdset_free(fds);
-
- safe_fclose(f);
+ f = NULL;
+ fds = NULL;
- return r;
+ return 0;
}
static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
@@ -1118,8 +1127,8 @@ static void test_mtab(void) {
log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. "
"This is not supported anymore. "
- "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output.");
- freeze();
+ "Please replace /etc/mtab with a symlink to /proc/self/mounts.");
+ freeze_or_reboot();
}
static void test_usr(void) {
@@ -1145,15 +1154,19 @@ static int initialize_join_controllers(void) {
return -ENOMEM;
arg_join_controllers[0] = strv_new("cpu", "cpuacct", NULL);
- arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL);
- arg_join_controllers[2] = NULL;
+ if (!arg_join_controllers[0])
+ goto oom;
- if (!arg_join_controllers[0] || !arg_join_controllers[1]) {
- free_join_controllers();
- return -ENOMEM;
- }
+ arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL);
+ if (!arg_join_controllers[1])
+ goto oom;
+ arg_join_controllers[2] = NULL;
return 0;
+
+oom:
+ arg_join_controllers = strv_free_free(arg_join_controllers);
+ return -ENOMEM;
}
static int enforce_syscall_archs(Set *archs) {
@@ -1397,7 +1410,7 @@ int main(int argc, char *argv[]) {
}
/* Initialize default unit */
- r = set_default_unit(SPECIAL_DEFAULT_TARGET);
+ r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET);
if (r < 0) {
log_emergency_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET);
error_message = "Failed to set default unit";
@@ -1674,8 +1687,7 @@ int main(int argc, char *argv[]) {
/* This will close all file descriptors that were opened, but
* not claimed by any unit. */
- fdset_free(fds);
- fds = NULL;
+ fds = fdset_free(fds);
arg_serialization = safe_fclose(arg_serialization);
@@ -1761,11 +1773,6 @@ int main(int argc, char *argv[]) {
switch (m->exit_code) {
- case MANAGER_EXIT:
- retval = EXIT_SUCCESS;
- log_debug("Exit.");
- goto finish;
-
case MANAGER_RELOAD:
log_info("Reloading.");
@@ -1807,11 +1814,21 @@ int main(int argc, char *argv[]) {
log_notice("Switching root.");
goto finish;
+ case MANAGER_EXIT:
+ retval = m->return_value;
+
+ if (m->running_as == MANAGER_USER) {
+ log_debug("Exit.");
+ goto finish;
+ }
+
+ /* fallthrough */
case MANAGER_REBOOT:
case MANAGER_POWEROFF:
case MANAGER_HALT:
case MANAGER_KEXEC: {
static const char * const table[_MANAGER_EXIT_CODE_MAX] = {
+ [MANAGER_EXIT] = "exit",
[MANAGER_REBOOT] = "reboot",
[MANAGER_POWEROFF] = "poweroff",
[MANAGER_HALT] = "halt",
@@ -1835,17 +1852,15 @@ finish:
if (m)
arg_shutdown_watchdog = m->shutdown_watchdog;
+
m = manager_free(m);
for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++)
arg_default_rlimit[j] = mfree(arg_default_rlimit[j]);
arg_default_unit = mfree(arg_default_unit);
-
- free_join_controllers();
-
+ arg_join_controllers = strv_free_free(arg_join_controllers);
arg_default_environment = strv_free(arg_default_environment);
-
arg_syscall_archs = set_free(arg_syscall_archs);
mac_selinux_finish();
@@ -1863,7 +1878,7 @@ finish:
* that the new systemd can pass the kernel default to
* its child processes */
if (saved_rlimit_nofile.rlim_cur > 0)
- setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile);
+ (void) setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile);
if (switch_root_dir) {
/* Kill all remaining processes from the
@@ -1905,10 +1920,10 @@ finish:
/* do not pass along the environment we inherit from the kernel or initrd */
if (switch_root_dir)
- clearenv();
+ (void) clearenv();
assert(i <= args_size);
- execv(args[0], (char* const*) args);
+ (void) execv(args[0], (char* const*) args);
}
/* Try the fallback, if there is any, without any
@@ -1918,14 +1933,10 @@ finish:
* but let's hope that doesn't matter.) */
arg_serialization = safe_fclose(arg_serialization);
-
- if (fds) {
- fdset_free(fds);
- fds = NULL;
- }
+ fds = fdset_free(fds);
/* Reopen the console */
- make_console_stdio();
+ (void) make_console_stdio();
for (j = 1, i = 1; j < (unsigned) argc; j++)
args[i++] = argv[j];
@@ -1939,30 +1950,26 @@ finish:
if (switch_root_init) {
args[0] = switch_root_init;
- execv(args[0], (char* const*) args);
+ (void) execv(args[0], (char* const*) args);
log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m");
}
args[0] = "/sbin/init";
- execv(args[0], (char* const*) args);
+ (void) execv(args[0], (char* const*) args);
if (errno == ENOENT) {
log_warning("No /sbin/init, trying fallback");
args[0] = "/bin/sh";
args[1] = NULL;
- execv(args[0], (char* const*) args);
+ (void) execv(args[0], (char* const*) args);
log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
} else
log_warning_errno(errno, "Failed to execute /sbin/init, giving up: %m");
}
arg_serialization = safe_fclose(arg_serialization);
-
- if (fds) {
- fdset_free(fds);
- fds = NULL;
- }
+ fds = fdset_free(fds);
#ifdef HAVE_VALGRIND_VALGRIND_H
/* If we are PID 1 and running under valgrind, then let's exit
@@ -1975,7 +1982,8 @@ finish:
if (shutdown_verb) {
char log_level[DECIMAL_STR_MAX(int) + 1];
- const char* command_line[9] = {
+ char exit_code[DECIMAL_STR_MAX(uint8_t) + 1];
+ const char* command_line[11] = {
SYSTEMD_SHUTDOWN_BINARY_PATH,
shutdown_verb,
"--log-level", log_level,
@@ -1990,6 +1998,7 @@ finish:
xsprintf(log_level, "%d", log_get_max_level());
switch (log_get_target()) {
+
case LOG_TARGET_KMSG:
case LOG_TARGET_JOURNAL_OR_KMSG:
case LOG_TARGET_SYSLOG_OR_KMSG:
@@ -2012,6 +2021,12 @@ finish:
if (log_get_show_location())
command_line[pos++] = "--log-location";
+ if (streq(shutdown_verb, "exit")) {
+ command_line[pos++] = "--exit-code";
+ command_line[pos++] = exit_code;
+ xsprintf(exit_code, "%d", retval);
+ }
+
assert(pos < ELEMENTSOF(command_line));
if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) {
@@ -2025,7 +2040,7 @@ finish:
/* Tell the binary how often to ping, ignore failure */
if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0)
- strv_push(&env_block, e);
+ (void) strv_push(&env_block, e);
} else
watchdog_close(true);
@@ -2043,9 +2058,9 @@ finish:
if (getpid() == 1) {
if (error_message)
manager_status_printf(NULL, STATUS_TYPE_EMERGENCY,
- ANSI_HIGHLIGHT_RED_ON "!!!!!!" ANSI_HIGHLIGHT_OFF,
+ ANSI_HIGHLIGHT_RED "!!!!!!" ANSI_NORMAL,
"%s, freezing.", error_message);
- freeze();
+ freeze_or_reboot();
}
return retval;
diff --git a/src/core/manager.c b/src/core/manager.c
index d918007bb8..b2d56e88a7 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -19,19 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <dirent.h>
#include <errno.h>
-#include <string.h>
+#include <fcntl.h>
+#include <linux/kd.h>
#include <signal.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <sys/inotify.h>
+#include <string.h>
#include <sys/epoll.h>
-#include <sys/reboot.h>
+#include <sys/inotify.h>
#include <sys/ioctl.h>
-#include <linux/kd.h>
-#include <fcntl.h>
-#include <dirent.h>
+#include <sys/reboot.h>
#include <sys/timerfd.h>
+#include <sys/wait.h>
+#include <unistd.h>
#ifdef HAVE_AUDIT
#include <libaudit.h>
@@ -40,40 +40,40 @@
#include "sd-daemon.h"
#include "sd-messages.h"
+#include "audit-fd.h"
+#include "boot-timestamps.h"
+#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
+#include "dbus-job.h"
+#include "dbus-manager.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "env-util.h"
+#include "exit-status.h"
#include "hashmap.h"
-#include "macro.h"
-#include "strv.h"
+#include "locale-setup.h"
#include "log.h"
-#include "util.h"
+#include "macro.h"
+#include "missing.h"
#include "mkdir.h"
+#include "path-lookup.h"
+#include "path-util.h"
+#include "process-util.h"
#include "ratelimit.h"
-#include "locale-setup.h"
-#include "unit-name.h"
-#include "missing.h"
#include "rm-rf.h"
-#include "path-lookup.h"
+#include "signal-util.h"
#include "special.h"
-#include "exit-status.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "time-util.h"
+#include "transaction.h"
+#include "unit-name.h"
+#include "util.h"
#include "virt.h"
#include "watchdog.h"
-#include "path-util.h"
-#include "audit-fd.h"
-#include "boot-timestamps.h"
-#include "env-util.h"
-#include "bus-common-errors.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "bus-kernel.h"
-#include "time-util.h"
-#include "process-util.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-#include "dbus.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
#include "manager.h"
-#include "transaction.h"
/* Initial delay and the interval for printing status messages about running jobs */
#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
@@ -111,7 +111,7 @@ static void manager_watch_jobs_in_progress(Manager *m) {
(void) sd_event_source_set_description(m->jobs_in_progress_event_source, "manager-jobs-in-progress");
}
-#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1))
+#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED)-1) + sizeof(ANSI_HIGHLIGHT_RED)-1 + 2*(sizeof(ANSI_NORMAL)-1))
static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
char *p = buffer;
@@ -122,23 +122,23 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po
if (pos > 1) {
if (pos > 2)
p = mempset(p, ' ', pos-2);
- p = stpcpy(p, ANSI_RED_ON);
+ p = stpcpy(p, ANSI_RED);
*p++ = '*';
}
if (pos > 0 && pos <= width) {
- p = stpcpy(p, ANSI_HIGHLIGHT_RED_ON);
+ p = stpcpy(p, ANSI_HIGHLIGHT_RED);
*p++ = '*';
}
- p = stpcpy(p, ANSI_HIGHLIGHT_OFF);
+ p = stpcpy(p, ANSI_NORMAL);
if (pos < width) {
- p = stpcpy(p, ANSI_RED_ON);
+ p = stpcpy(p, ANSI_RED);
*p++ = '*';
if (pos < width-1)
p = mempset(p, ' ', width-1-pos);
- strcpy(p, ANSI_HIGHLIGHT_OFF);
+ strcpy(p, ANSI_NORMAL);
}
}
@@ -317,6 +317,8 @@ static int manager_watch_idle_pipe(Manager *m) {
static void manager_close_idle_pipe(Manager *m) {
assert(m);
+ m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
+
safe_close_pair(m->idle_pipe);
safe_close_pair(m->idle_pipe + 2);
}
@@ -493,6 +495,7 @@ static void manager_clean_environment(Manager *m) {
"MANAGERPID",
"LISTEN_PID",
"LISTEN_FDS",
+ "LISTEN_FDNAMES",
"WATCHDOG_PID",
"WATCHDOG_USEC",
NULL);
@@ -569,14 +572,16 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd =
- m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd =
- m->cgroup_inotify_fd = -1;
+ m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd = -1;
+
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
m->ask_password_inotify_fd = -1;
m->have_ask_password = -EINVAL; /* we don't know */
m->first_boot = -1;
+ m->cgroup_netclass_registry_last = CGROUP_NETCLASS_FIXED_MAX;
+
m->test_run = test_run;
/* Reboot immediately if the user hits C-A-D more often than 7x per 2s */
@@ -602,14 +607,6 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
if (r < 0)
goto fail;
- r = set_ensure_allocated(&m->startup_units, NULL);
- if (r < 0)
- goto fail;
-
- r = set_ensure_allocated(&m->failed_units, NULL);
- if (r < 0)
- goto fail;
-
r = sd_event_default(&m->event);
if (r < 0)
goto fail;
@@ -944,7 +941,6 @@ Manager* manager_free(Manager *m) {
sd_event_source_unref(m->notify_event_source);
sd_event_source_unref(m->time_change_event_source);
sd_event_source_unref(m->jobs_in_progress_event_source);
- sd_event_source_unref(m->idle_pipe_event_source);
sd_event_source_unref(m->run_queue_event_source);
safe_close(m->signal_fd);
@@ -967,6 +963,8 @@ Manager* manager_free(Manager *m) {
hashmap_free(m->cgroup_unit);
set_free_free(m->unit_path_cache);
+ hashmap_free(m->cgroup_netclass_registry);
+
free(m->switch_root);
free(m->switch_root_init);
@@ -1074,8 +1072,7 @@ static void manager_build_unit_path_cache(Manager *m) {
goto fail;
}
- closedir(d);
- d = NULL;
+ d = safe_closedir(d);
}
return;
@@ -1962,7 +1959,6 @@ static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32
m->no_console_output = m->n_on_console > 0;
- m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
manager_close_idle_pipe(m);
return 0;
@@ -2675,9 +2671,6 @@ static void manager_notify_finished(Manager *m) {
}
void manager_check_finished(Manager *m) {
- Unit *u = NULL;
- Iterator i;
-
assert(m);
if (m->n_reloading > 0)
@@ -2690,11 +2683,9 @@ void manager_check_finished(Manager *m) {
return;
if (hashmap_size(m->jobs) > 0) {
-
if (m->jobs_in_progress_event_source)
/* Ignore any failure, this is only for feedback */
- (void) sd_event_source_set_time(m->jobs_in_progress_event_source,
- now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
+ (void) sd_event_source_set_time(m->jobs_in_progress_event_source, now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
return;
}
@@ -2702,7 +2693,6 @@ void manager_check_finished(Manager *m) {
manager_flip_auto_status(m, false);
/* Notify Type=idle units that we are done now */
- m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
manager_close_idle_pipe(m);
/* Turn off confirm spawn now */
@@ -2721,9 +2711,7 @@ void manager_check_finished(Manager *m) {
manager_notify_finished(m);
- SET_FOREACH(u, m->startup_units, i)
- if (u->cgroup_path)
- cgroup_context_apply(unit_get_cgroup_context(u), unit_get_own_mask(u), u->cgroup_path, manager_state(m));
+ manager_invalidate_startup_units(m);
}
static int create_generator_dir(Manager *m, char **generator, const char *name) {
@@ -3025,30 +3013,6 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons
va_end(ap);
}
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) {
- _cleanup_free_ char *p = NULL;
- Unit *found;
- int r;
-
- assert(m);
- assert(path);
- assert(suffix);
- assert(_found);
-
- r = unit_name_from_path(path, suffix, &p);
- if (r < 0)
- return r;
-
- found = manager_get_unit(m, p);
- if (!found) {
- *_found = NULL;
- return 0;
- }
-
- *_found = found;
- return 1;
-}
-
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
char p[strlen(path)+1];
@@ -3069,8 +3033,9 @@ const char *manager_get_runtime_prefix(Manager *m) {
getenv("XDG_RUNTIME_DIR");
}
-void manager_update_failed_units(Manager *m, Unit *u, bool failed) {
+int manager_update_failed_units(Manager *m, Unit *u, bool failed) {
unsigned size;
+ int r;
assert(m);
assert(u->manager == m);
@@ -3078,13 +3043,19 @@ void manager_update_failed_units(Manager *m, Unit *u, bool failed) {
size = set_size(m->failed_units);
if (failed) {
+ r = set_ensure_allocated(&m->failed_units, NULL);
+ if (r < 0)
+ return log_oom();
+
if (set_put(m->failed_units, u) < 0)
- log_oom();
+ return log_oom();
} else
- set_remove(m->failed_units, u);
+ (void) set_remove(m->failed_units, u);
if (set_size(m->failed_units) != size)
bus_manager_send_change_signal(m);
+
+ return 0;
}
ManagerState manager_state(Manager *m) {
diff --git a/src/core/manager.h b/src/core/manager.h
index 9956cb7700..38d2770e97 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -23,11 +23,12 @@
#include <stdbool.h>
#include <stdio.h>
+#include <libmount.h>
#include "sd-bus.h"
#include "sd-event.h"
-#include "fdset.h"
#include "cgroup-util.h"
+#include "fdset.h"
#include "hashmap.h"
#include "list.h"
#include "ratelimit.h"
@@ -68,11 +69,11 @@ typedef enum StatusType {
STATUS_TYPE_EMERGENCY,
} StatusType;
+#include "execute.h"
#include "job.h"
#include "path-lookup.h"
-#include "execute.h"
-#include "unit-name.h"
#include "show-status.h"
+#include "unit-name.h"
struct Manager {
/* Note that the set of units we know of is allowed to be
@@ -176,10 +177,8 @@ struct Manager {
Hashmap *devices_by_sysfs;
/* Data specific to the mount subsystem */
- FILE *proc_self_mountinfo;
+ struct libmnt_monitor *mount_monitor;
sd_event_source *mount_event_source;
- int utab_inotify_fd;
- sd_event_source *mount_utab_event_source;
/* Data specific to the swap filesystem */
FILE *proc_swaps;
@@ -242,6 +241,11 @@ struct Manager {
bool test_run:1;
+ /* If non-zero, exit with the following value when the systemd
+ * process terminate. Useful for containers: systemd-nspawn could get
+ * the return value. */
+ uint8_t return_value;
+
ShowStatus show_status;
bool confirm_spawn;
bool no_console_output;
@@ -256,6 +260,7 @@ struct Manager {
bool default_cpu_accounting;
bool default_memory_accounting;
bool default_blockio_accounting;
+ bool default_tasks_accounting;
usec_t default_timer_accuracy_usec;
@@ -302,6 +307,10 @@ struct Manager {
const char *unit_log_format_string;
int first_boot;
+
+ /* Used for NetClass=auto units */
+ Hashmap *cgroup_netclass_registry;
+ uint32_t cgroup_netclass_registry_last;
};
int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);
@@ -313,8 +322,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
Job *manager_get_job(Manager *m, uint32_t id);
Unit *manager_get_unit(Manager *m, const char *name);
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found);
-
int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j);
int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
@@ -368,7 +375,7 @@ const char *manager_get_runtime_prefix(Manager *m);
ManagerState manager_state(Manager *m);
-void manager_update_failed_units(Manager *m, Unit *u, bool failed);
+int manager_update_failed_units(Manager *m, Unit *u, bool failed);
const char *manager_state_to_string(ManagerState m) _const_;
ManagerState manager_state_from_string(const char *s) _pure_;
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 65f3d06ad0..9b16eaa0e2 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -208,7 +208,7 @@ int mount_setup_early(void) {
int j;
j = mount_one(mount_table + i, false);
- if (r == 0)
+ if (j != 0 && r >= 0)
r = j;
}
@@ -351,7 +351,7 @@ int mount_setup(bool loaded_policy) {
int j;
j = mount_one(mount_table + i, loaded_policy);
- if (r == 0)
+ if (j != 0 && r >= 0)
r = j;
}
diff --git a/src/core/mount.c b/src/core/mount.c
index 1f02aa5566..8611129453 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -23,8 +23,6 @@
#include <stdio.h>
#include <sys/epoll.h>
#include <signal.h>
-#include <libmount.h>
-#include <sys/inotify.h>
#include "manager.h"
#include "unit.h"
@@ -696,6 +694,9 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(m);
@@ -1535,13 +1536,13 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
}
static void mount_shutdown(Manager *m) {
+
assert(m);
m->mount_event_source = sd_event_source_unref(m->mount_event_source);
- m->mount_utab_event_source = sd_event_source_unref(m->mount_utab_event_source);
- m->proc_self_mountinfo = safe_fclose(m->proc_self_mountinfo);
- m->utab_inotify_fd = safe_close(m->utab_inotify_fd);
+ mnt_unref_monitor(m->mount_monitor);
+ m->mount_monitor = NULL;
}
static int mount_get_timeout(Unit *u, uint64_t *timeout) {
@@ -1560,53 +1561,41 @@ static int mount_get_timeout(Unit *u, uint64_t *timeout) {
static int mount_enumerate(Manager *m) {
int r;
+
assert(m);
mnt_init_debug(0);
- if (!m->proc_self_mountinfo) {
- m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
- if (!m->proc_self_mountinfo)
- return -errno;
+ if (!m->mount_monitor) {
+ int fd;
- r = sd_event_add_io(m->event, &m->mount_event_source, fileno(m->proc_self_mountinfo), EPOLLPRI, mount_dispatch_io, m);
- if (r < 0)
+ m->mount_monitor = mnt_new_monitor();
+ if (!m->mount_monitor) {
+ r = -ENOMEM;
goto fail;
+ }
- /* Dispatch this before we dispatch SIGCHLD, so that
- * we always get the events from /proc/self/mountinfo
- * before the SIGCHLD of /usr/bin/mount. */
- r = sd_event_source_set_priority(m->mount_event_source, -10);
+ r = mnt_monitor_enable_kernel(m->mount_monitor, 1);
if (r < 0)
goto fail;
-
- (void) sd_event_source_set_description(m->mount_event_source, "mount-mountinfo-dispatch");
- }
-
- if (m->utab_inotify_fd < 0) {
- m->utab_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (m->utab_inotify_fd < 0) {
- r = -errno;
+ r = mnt_monitor_enable_userspace(m->mount_monitor, 1, NULL);
+ if (r < 0)
goto fail;
- }
- (void) mkdir_p_label("/run/mount", 0755);
-
- r = inotify_add_watch(m->utab_inotify_fd, "/run/mount", IN_MOVED_TO);
- if (r < 0) {
- r = -errno;
+ /* mnt_unref_monitor() will close the fd */
+ fd = r = mnt_monitor_get_fd(m->mount_monitor);
+ if (r < 0)
goto fail;
- }
- r = sd_event_add_io(m->event, &m->mount_utab_event_source, m->utab_inotify_fd, EPOLLIN, mount_dispatch_io, m);
+ r = sd_event_add_io(m->event, &m->mount_event_source, fd, EPOLLIN, mount_dispatch_io, m);
if (r < 0)
goto fail;
- r = sd_event_source_set_priority(m->mount_utab_event_source, -10);
+ r = sd_event_source_set_priority(m->mount_event_source, -10);
if (r < 0)
goto fail;
- (void) sd_event_source_set_description(m->mount_utab_event_source, "mount-utab-dispatch");
+ (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
}
r = mount_load_proc_self_mountinfo(m, false);
@@ -1629,45 +1618,27 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
int r;
assert(m);
- assert(revents & (EPOLLPRI | EPOLLIN));
-
- /* The manager calls this for every fd event happening on the
- * /proc/self/mountinfo file, which informs us about mounting
- * table changes, and for /run/mount events which we watch
- * for mount options. */
+ assert(revents & EPOLLIN);
- if (fd == m->utab_inotify_fd) {
+ if (fd == mnt_monitor_get_fd(m->mount_monitor)) {
bool rescan = false;
- /* FIXME: We *really* need to replace this with
- * libmount's own API for this, we should not hardcode
- * internal behaviour of libmount here. */
-
- for (;;) {
- union inotify_event_buffer buffer;
- struct inotify_event *e;
- ssize_t l;
-
- l = read(fd, &buffer, sizeof(buffer));
- if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
- break;
-
- log_error_errno(errno, "Failed to read utab inotify: %m");
- break;
- }
-
- FOREACH_INOTIFY_EVENT(e, buffer, l) {
- /* Only care about changes to utab,
- * but we have to monitor the
- * directory to reliably get
- * notifications about when utab is
- * replaced using rename(2) */
- if ((e->mask & IN_Q_OVERFLOW) || streq(e->name, "utab"))
- rescan = true;
- }
- }
-
+ /* Drain all events and verify that the event is valid.
+ *
+ * Note that libmount also monitors /run/mount mkdir if the
+ * directory does not exist yet. The mkdir may generate event
+ * which is irrelevant for us.
+ *
+ * error: r < 0; valid: r == 0, false positive: rc == 1 */
+ do {
+ r = mnt_monitor_next_change(m->mount_monitor, NULL, NULL);
+ if (r == 0)
+ rescan = true;
+ else if (r < 0)
+ return log_error_errno(r, "Failed to drain libmount events");
+ } while (r == 0);
+
+ log_debug("libmount event [rescan: %s]", yes_no(rescan));
if (!rescan)
return 0;
}
@@ -1788,24 +1759,6 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
}
-static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
- [MOUNT_DEAD] = "dead",
- [MOUNT_MOUNTING] = "mounting",
- [MOUNT_MOUNTING_DONE] = "mounting-done",
- [MOUNT_MOUNTED] = "mounted",
- [MOUNT_REMOUNTING] = "remounting",
- [MOUNT_UNMOUNTING] = "unmounting",
- [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
- [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
- [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
- [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
- [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
- [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
- [MOUNT_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
-
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
[MOUNT_EXEC_MOUNT] = "ExecMount",
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
diff --git a/src/core/mount.h b/src/core/mount.h
index 280ea0d638..83d14ae713 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -26,24 +26,6 @@ typedef struct Mount Mount;
#include "kill.h"
#include "execute.h"
-typedef enum MountState {
- MOUNT_DEAD,
- MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */
- MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */
- MOUNT_MOUNTED,
- MOUNT_REMOUNTING,
- MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_FAILED,
- _MOUNT_STATE_MAX,
- _MOUNT_STATE_INVALID = -1
-} MountState;
-
typedef enum MountExecCommand {
MOUNT_EXEC_MOUNT,
MOUNT_EXEC_UNMOUNT,
@@ -120,9 +102,6 @@ extern const UnitVTable mount_vtable;
void mount_fd_event(Manager *m, int events);
-const char* mount_state_to_string(MountState i) _const_;
-MountState mount_state_from_string(const char *s) _pure_;
-
const char* mount_exec_command_to_string(MountExecCommand i) _const_;
MountExecCommand mount_exec_command_from_string(const char *s) _pure_;
diff --git a/src/core/namespace.c b/src/core/namespace.c
index eb88574f8f..2b8b707df5 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -643,16 +643,7 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
int setup_netns(int netns_storage_socket[2]) {
_cleanup_close_ int netns = -1;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- int r;
+ int r, q;
assert(netns_storage_socket);
assert(netns_storage_socket[0] >= 0);
@@ -669,12 +660,8 @@ int setup_netns(int netns_storage_socket[2]) {
if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
return -errno;
- if (recvmsg(netns_storage_socket[0], &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) < 0) {
- if (errno != EAGAIN) {
- r = -errno;
- goto fail;
- }
-
+ netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
+ if (netns == -EAGAIN) {
/* Nothing stored yet, so let's create a new namespace */
if (unshare(CLONE_NEWNET) < 0) {
@@ -691,15 +678,13 @@ int setup_netns(int netns_storage_socket[2]) {
}
r = 1;
- } else {
- /* Yay, found something, so let's join the namespace */
- CMSG_FOREACH(cmsg, &mh)
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
- netns = *(int*) CMSG_DATA(cmsg);
- }
+ } else if (netns < 0) {
+ r = netns;
+ goto fail;
+ } else {
+ /* Yay, found something, so let's join the namespace */
if (setns(netns, CLONE_NEWNET) < 0) {
r = -errno;
goto fail;
@@ -708,21 +693,14 @@ int setup_netns(int netns_storage_socket[2]) {
r = 0;
}
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &netns, sizeof(int));
- mh.msg_controllen = cmsg->cmsg_len;
-
- if (sendmsg(netns_storage_socket[1], &mh, MSG_DONTWAIT|MSG_NOSIGNAL) < 0) {
- r = -errno;
+ q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
+ if (q < 0) {
+ r = q;
goto fail;
}
fail:
lockf(netns_storage_socket[0], F_ULOCK, 0);
-
return r;
}
diff --git a/src/core/path.c b/src/core/path.c
index e9111d0612..081ac2040d 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -715,15 +715,6 @@ static void path_reset_failed(Unit *u) {
p->result = PATH_SUCCESS;
}
-static const char* const path_state_table[_PATH_STATE_MAX] = {
- [PATH_DEAD] = "dead",
- [PATH_WAITING] = "waiting",
- [PATH_RUNNING] = "running",
- [PATH_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
-
static const char* const path_type_table[_PATH_TYPE_MAX] = {
[PATH_EXISTS] = "PathExists",
[PATH_EXISTS_GLOB] = "PathExistsGlob",
diff --git a/src/core/path.h b/src/core/path.h
index dec39333e4..deb9bab1e5 100644
--- a/src/core/path.h
+++ b/src/core/path.h
@@ -26,15 +26,6 @@ typedef struct PathSpec PathSpec;
#include "unit.h"
-typedef enum PathState {
- PATH_DEAD,
- PATH_WAITING,
- PATH_RUNNING,
- PATH_FAILED,
- _PATH_STATE_MAX,
- _PATH_STATE_INVALID = -1
-} PathState;
-
typedef enum PathType {
PATH_EXISTS,
PATH_EXISTS_GLOB,
@@ -96,9 +87,6 @@ void path_free_specs(Path *p);
extern const UnitVTable path_vtable;
-const char* path_state_to_string(PathState i) _const_;
-PathState path_state_from_string(const char *s) _pure_;
-
const char* path_type_to_string(PathType i) _const_;
PathType path_type_from_string(const char *s) _pure_;
diff --git a/src/core/scope.c b/src/core/scope.c
index 98395becfd..ea7d846578 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -534,6 +534,9 @@ static int scope_enumerate(Manager *m) {
u->transient = true;
u->default_dependencies = false;
u->no_gc = true;
+ u->ignore_on_isolate = true;
+ u->refuse_manual_start = true;
+ u->refuse_manual_stop = true;
SCOPE(u)->deserialized_state = SCOPE_RUNNING;
SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14;
@@ -549,17 +552,6 @@ static int scope_enumerate(Manager *m) {
return 0;
}
-static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
- [SCOPE_DEAD] = "dead",
- [SCOPE_RUNNING] = "running",
- [SCOPE_ABANDONED] = "abandoned",
- [SCOPE_STOP_SIGTERM] = "stop-sigterm",
- [SCOPE_STOP_SIGKILL] = "stop-sigkill",
- [SCOPE_FAILED] = "failed",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
-
static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
[SCOPE_SUCCESS] = "success",
[SCOPE_FAILURE_RESOURCES] = "resources",
diff --git a/src/core/scope.h b/src/core/scope.h
index 4452fe2c94..f838ee5357 100644
--- a/src/core/scope.h
+++ b/src/core/scope.h
@@ -25,17 +25,6 @@ typedef struct Scope Scope;
#include "kill.h"
-typedef enum ScopeState {
- SCOPE_DEAD,
- SCOPE_RUNNING,
- SCOPE_ABANDONED,
- SCOPE_STOP_SIGTERM,
- SCOPE_STOP_SIGKILL,
- SCOPE_FAILED,
- _SCOPE_STATE_MAX,
- _SCOPE_STATE_INVALID = -1
-} ScopeState;
-
typedef enum ScopeResult {
SCOPE_SUCCESS,
SCOPE_FAILURE_RESOURCES,
@@ -64,8 +53,5 @@ extern const UnitVTable scope_vtable;
int scope_abandon(Scope *s);
-const char* scope_state_to_string(ScopeState i) _const_;
-ScopeState scope_state_from_string(const char *s) _pure_;
-
const char* scope_result_to_string(ScopeResult i) _const_;
ScopeResult scope_result_from_string(const char *s) _pure_;
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index e5b457643b..ff1ea23528 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -78,14 +78,14 @@ int mac_selinux_setup(bool *loaded_policy) {
before_load = now(CLOCK_MONOTONIC);
r = selinux_init_load_policy(&enforce);
if (r == 0) {
+ _cleanup_(mac_selinux_freep) char *label = NULL;
char timespan[FORMAT_TIMESPAN_MAX];
- char *label;
mac_selinux_retest();
/* Transition to the new context */
r = mac_selinux_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label);
- if (r < 0 || label == NULL) {
+ if (r < 0 || !label) {
log_open();
log_error("Failed to compute init label, ignoring.");
} else {
@@ -94,8 +94,6 @@ int mac_selinux_setup(bool *loaded_policy) {
log_open();
if (r < 0)
log_error("Failed to transition into init label '%s', ignoring.", label);
-
- mac_selinux_free(label);
}
after_load = now(CLOCK_MONOTONIC);
diff --git a/src/core/service.c b/src/core/service.c
index 248a9e8c62..1e4f707bf4 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -108,6 +108,7 @@ static void service_init(Unit *u) {
s->type = _SERVICE_TYPE_INVALID;
s->socket_fd = -1;
s->bus_endpoint_fd = -1;
+ s->stdin_fd = s->stdout_fd = s->stderr_fd = -1;
s->guess_main_pid = true;
RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst);
@@ -261,6 +262,7 @@ static void service_fd_store_unlink(ServiceFDStore *fs) {
sd_event_source_unref(fs->event_source);
}
+ free(fs->fdname);
safe_close(fs->fd);
free(fs);
}
@@ -270,11 +272,15 @@ static void service_release_resources(Unit *u) {
assert(s);
- if (!s->fd_store)
+ if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0)
return;
log_unit_debug(u, "Releasing all resources.");
+ s->stdin_fd = safe_close(s->stdin_fd);
+ s->stdout_fd = safe_close(s->stdout_fd);
+ s->stderr_fd = safe_close(s->stderr_fd);
+
while (s->fd_store)
service_fd_store_unlink(s->fd_store);
@@ -334,7 +340,7 @@ static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *us
return 0;
}
-static int service_add_fd_store(Service *s, int fd) {
+static int service_add_fd_store(Service *s, int fd, const char *name) {
ServiceFDStore *fs;
int r;
@@ -361,9 +367,15 @@ static int service_add_fd_store(Service *s, int fd) {
fs->fd = fd;
fs->service = s;
+ fs->fdname = strdup(name ?: "stored");
+ if (!fs->fdname) {
+ free(fs);
+ return -ENOMEM;
+ }
r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
if (r < 0) {
+ free(fs->fdname);
free(fs);
return r;
}
@@ -376,7 +388,7 @@ static int service_add_fd_store(Service *s, int fd) {
return 1;
}
-static int service_add_fd_store_set(Service *s, FDSet *fds) {
+static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
int r;
assert(s);
@@ -391,7 +403,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) {
if (fd < 0)
break;
- r = service_add_fd_store(s, fd);
+ r = service_add_fd_store(s, fd, name);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m");
if (r > 0) {
@@ -482,6 +494,12 @@ static int service_verify(Service *s) {
return -EINVAL;
}
+ if (s->usb_function_descriptors && !s->usb_function_strings)
+ log_unit_warning(UNIT(s), "Service has USBFunctionDescriptors= setting, but no USBFunctionStrings=. Ignoring.");
+
+ if (!s->usb_function_descriptors && s->usb_function_strings)
+ log_unit_warning(UNIT(s), "Service has USBFunctionStrings= setting, but no USBFunctionDescriptors=. Ignoring.");
+
return 0;
}
@@ -878,7 +896,6 @@ static void service_set_state(Service *s, ServiceState state) {
log_unit_debug(UNIT(s), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state));
unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
- s->reload_result = SERVICE_SUCCESS;
}
static int service_coldplug(Unit *u) {
@@ -951,62 +968,79 @@ static int service_coldplug(Unit *u) {
return 0;
}
-static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
+static int service_collect_fds(Service *s, int **fds, char ***fd_names) {
+ _cleanup_strv_free_ char **rfd_names = NULL;
_cleanup_free_ int *rfds = NULL;
- unsigned rn_fds = 0;
- Iterator i;
- int r;
- Unit *u;
+ int rn_fds = 0, r;
assert(s);
assert(fds);
- assert(n_fds);
+ assert(fd_names);
- if (s->socket_fd >= 0)
- return 0;
+ if (s->socket_fd >= 0) {
- SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
- int *cfds;
- unsigned cn_fds;
- Socket *sock;
+ /* Pass the per-connection socket */
- if (u->type != UNIT_SOCKET)
- continue;
+ rfds = new(int, 1);
+ if (!rfds)
+ return -ENOMEM;
+ rfds[0] = s->socket_fd;
- sock = SOCKET(u);
+ rfd_names = strv_new("connection", NULL);
+ if (!rfd_names)
+ return -ENOMEM;
- r = socket_collect_fds(sock, &cfds, &cn_fds);
- if (r < 0)
- return r;
+ rn_fds = 1;
+ } else {
+ Iterator i;
+ Unit *u;
- if (cn_fds <= 0) {
- free(cfds);
- continue;
- }
+ /* Pass all our configured sockets for singleton services */
- if (!rfds) {
- rfds = cfds;
- rn_fds = cn_fds;
- } else {
- int *t;
+ SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
+ _cleanup_free_ int *cfds = NULL;
+ Socket *sock;
+ int cn_fds;
- t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
- if (!t) {
- free(cfds);
- return -ENOMEM;
- }
+ if (u->type != UNIT_SOCKET)
+ continue;
+
+ sock = SOCKET(u);
+
+ cn_fds = socket_collect_fds(sock, &cfds);
+ if (cn_fds < 0)
+ return cn_fds;
+
+ if (cn_fds <= 0)
+ continue;
+
+ if (!rfds) {
+ rfds = cfds;
+ rn_fds = cn_fds;
+
+ cfds = NULL;
+ } else {
+ int *t;
+
+ t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
+ if (!t)
+ return -ENOMEM;
- memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
- rfds = t;
- rn_fds += cn_fds;
+ memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
- free(cfds);
+ rfds = t;
+ rn_fds += cn_fds;
+ }
+ r = strv_extend_n(&rfd_names, socket_fdname(sock), cn_fds);
+ if (r < 0)
+ return r;
}
}
if (s->n_fd_store > 0) {
ServiceFDStore *fs;
+ char **nl;
int *t;
t = realloc(rfds, (rn_fds + s->n_fd_store) * sizeof(int));
@@ -1014,15 +1048,32 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
return -ENOMEM;
rfds = t;
- LIST_FOREACH(fd_store, fs, s->fd_store)
- rfds[rn_fds++] = fs->fd;
+
+ nl = realloc(rfd_names, (rn_fds + s->n_fd_store + 1) * sizeof(char*));
+ if (!nl)
+ return -ENOMEM;
+
+ rfd_names = nl;
+
+ LIST_FOREACH(fd_store, fs, s->fd_store) {
+ rfds[rn_fds] = fs->fd;
+ rfd_names[rn_fds] = strdup(strempty(fs->fdname));
+ if (!rfd_names[rn_fds])
+ return -ENOMEM;
+
+ rn_fds++;
+ }
+
+ rfd_names[rn_fds] = NULL;
}
*fds = rfds;
- *n_fds = rn_fds;
+ *fd_names = rfd_names;
rfds = NULL;
- return 0;
+ rfd_names = NULL;
+
+ return rn_fds;
}
static int service_spawn(
@@ -1036,23 +1087,25 @@ static int service_spawn(
bool is_control,
pid_t *_pid) {
- pid_t pid;
- int r;
- int *fds = NULL;
- _cleanup_free_ int *fdsbuf = NULL;
- unsigned n_fds = 0, n_env = 0;
+ _cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
_cleanup_free_ char *bus_endpoint_path = NULL;
- _cleanup_strv_free_ char
- **argv = NULL, **final_env = NULL, **our_env = NULL;
+ _cleanup_free_ int *fds = NULL;
+ unsigned n_fds = 0, n_env = 0;
const char *path;
+ pid_t pid;
+
ExecParameters exec_params = {
- .apply_permissions = apply_permissions,
- .apply_chroot = apply_chroot,
- .apply_tty_stdin = apply_tty_stdin,
- .bus_endpoint_fd = -1,
- .selinux_context_net = s->socket_fd_selinux_context_net
+ .apply_permissions = apply_permissions,
+ .apply_chroot = apply_chroot,
+ .apply_tty_stdin = apply_tty_stdin,
+ .bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
+ int r;
+
assert(s);
assert(c);
assert(_pid);
@@ -1072,16 +1125,11 @@ static int service_spawn(
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
- if (s->socket_fd >= 0) {
- fds = &s->socket_fd;
- n_fds = 1;
- } else {
- r = service_collect_fds(s, &fdsbuf, &n_fds);
- if (r < 0)
- goto fail;
+ r = service_collect_fds(s, &fds, &fd_names);
+ if (r < 0)
+ goto fail;
- fds = fdsbuf;
- }
+ n_fds = r;
}
if (timeout > 0) {
@@ -1119,7 +1167,7 @@ static int service_spawn(
goto fail;
}
- if (UNIT_DEREF(s->accept_socket)) {
+ if (s->socket_fd >= 0) {
union sockaddr_union sa;
socklen_t salen = sizeof(sa);
@@ -1185,6 +1233,7 @@ static int service_spawn(
exec_params.argv = argv;
exec_params.fds = fds;
+ exec_params.fd_names = fd_names;
exec_params.n_fds = n_fds;
exec_params.environment = final_env;
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
@@ -1194,8 +1243,12 @@ static int service_spawn(
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
exec_params.watchdog_usec = s->watchdog_usec;
exec_params.bus_endpoint_path = bus_endpoint_path;
+ exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
if (s->type == SERVICE_IDLE)
exec_params.idle_pipe = UNIT(s)->manager->idle_pipe;
+ exec_params.stdin_fd = s->stdin_fd;
+ exec_params.stdout_fd = s->stdout_fd;
+ exec_params.stderr_fd = s->stderr_fd;
r = exec_spawn(UNIT(s),
c,
@@ -1772,6 +1825,7 @@ static void service_enter_reload(Service *s) {
assert(s);
service_unwatch_control_pid(s);
+ s->reload_result = SERVICE_SUCCESS;
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
if (s->control_command) {
@@ -1995,6 +2049,7 @@ _pure_ static bool service_can_reload(Unit *u) {
static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
Service *s = SERVICE(u);
ServiceFDStore *fs;
+ int r;
assert(u);
assert(f);
@@ -2013,12 +2068,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good));
- if (s->status_text) {
- _cleanup_free_ char *c = NULL;
-
- c = cescape(s->status_text);
- unit_serialize_item(u, f, "status-text", strempty(c));
- }
+ r = unit_serialize_item_escaped(u, f, "status-text", s->status_text);
+ if (r < 0)
+ return r;
/* FIXME: There's a minor uncleanliness here: if there are
* multiple commands attached here, we will start from the
@@ -2026,34 +2078,34 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (s->control_command_id >= 0)
unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
- if (s->socket_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, s->socket_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
- }
-
- if (s->bus_endpoint_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, s->bus_endpoint_fd);
- if (copy < 0)
- return copy;
+ r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd);
+ if (r < 0)
+ return r;
+ r = unit_serialize_item_fd(u, f, fds, "stdout-fd", s->stdout_fd);
+ if (r < 0)
+ return r;
+ r = unit_serialize_item_fd(u, f, fds, "stderr-fd", s->stderr_fd);
+ if (r < 0)
+ return r;
- unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy);
- }
+ r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd);
+ if (r < 0)
+ return r;
+ r = unit_serialize_item_fd(u, f, fds, "endpoint-fd", s->bus_endpoint_fd);
+ if (r < 0)
+ return r;
LIST_FOREACH(fd_store, fs, s->fd_store) {
+ _cleanup_free_ char *c = NULL;
int copy;
copy = fdset_put_dup(fds, fs->fd);
if (copy < 0)
return copy;
- unit_serialize_item_format(u, f, "fd-store-fd", "%i", copy);
+ c = cescape(fs->fdname);
+
+ unit_serialize_item_format(u, f, "fd-store-fd", "%i %s", copy, strempty(c));
}
if (s->main_exec_status.pid > 0) {
@@ -2070,8 +2122,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (dual_timestamp_is_set(&s->watchdog_timestamp))
dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
- if (s->forbid_restart)
- unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
+ unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
return 0;
}
@@ -2183,12 +2234,24 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
s->bus_endpoint_fd = fdset_remove(fds, fd);
}
} else if (streq(key, "fd-store-fd")) {
+ const char *fdv;
+ size_t pf;
int fd;
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ pf = strcspn(value, WHITESPACE);
+ fdv = strndupa(value, pf);
+
+ if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
else {
- r = service_add_fd_store(s, fd);
+ _cleanup_free_ char *t = NULL;
+ const char *fdn;
+
+ fdn = value + pf;
+ fdn += strspn(fdn, WHITESPACE);
+ (void) cunescape(fdn, 0, &t);
+
+ r = service_add_fd_store(s, fd, t);
if (r < 0)
log_unit_error_errno(u, r, "Failed to add fd to store: %m");
else if (r > 0)
@@ -2230,6 +2293,33 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug(u, "Failed to parse forbid-restart value: %s", value);
else
s->forbid_restart = b;
+ } else if (streq(key, "stdin-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse stdin-fd value: %s", value);
+ else {
+ asynchronous_close(s->stdin_fd);
+ s->stdin_fd = fdset_remove(fds, fd);
+ }
+ } else if (streq(key, "stdout-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse stdout-fd value: %s", value);
+ else {
+ asynchronous_close(s->stdout_fd);
+ s->stdout_fd = fdset_remove(fds, fd);
+ }
+ } else if (streq(key, "stderr-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse stderr-fd value: %s", value);
+ else {
+ asynchronous_close(s->stderr_fd);
+ s->stderr_fd = fdset_remove(fds, fd);
+ }
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -2737,6 +2827,8 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
case SERVICE_RELOAD:
log_unit_warning(UNIT(s), "Reload operation timed out. Stopping.");
+ service_unwatch_control_pid(s);
+ service_kill_control_processes(s);
s->reload_result = SERVICE_FAILURE_TIMEOUT;
service_enter_running(s, SERVICE_SUCCESS);
break;
@@ -2940,8 +3032,17 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
if (strv_find(tags, "WATCHDOG=1"))
service_reset_watchdog(s);
- if (strv_find(tags, "FDSTORE=1"))
- service_add_fd_store_set(s, fds);
+ if (strv_find(tags, "FDSTORE=1")) {
+ const char *name;
+
+ name = strv_find_startswith(tags, "FDNAME=");
+ if (name && !fdname_is_valid(name)) {
+ log_unit_warning(u, "Passed FDNAME= name is invalid, ignoring.");
+ name = NULL;
+ }
+
+ service_add_fd_store_set(s, fds, name);
+ }
/* Notify clients about changed status or main pid */
if (notify_dbus)
@@ -3084,27 +3185,6 @@ static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error);
}
-static const char* const service_state_table[_SERVICE_STATE_MAX] = {
- [SERVICE_DEAD] = "dead",
- [SERVICE_START_PRE] = "start-pre",
- [SERVICE_START] = "start",
- [SERVICE_START_POST] = "start-post",
- [SERVICE_RUNNING] = "running",
- [SERVICE_EXITED] = "exited",
- [SERVICE_RELOAD] = "reload",
- [SERVICE_STOP] = "stop",
- [SERVICE_STOP_SIGABRT] = "stop-sigabrt",
- [SERVICE_STOP_SIGTERM] = "stop-sigterm",
- [SERVICE_STOP_SIGKILL] = "stop-sigkill",
- [SERVICE_STOP_POST] = "stop-post",
- [SERVICE_FINAL_SIGTERM] = "final-sigterm",
- [SERVICE_FINAL_SIGKILL] = "final-sigkill",
- [SERVICE_FAILED] = "failed",
- [SERVICE_AUTO_RESTART] = "auto-restart",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
-
static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
[SERVICE_RESTART_NO] = "no",
[SERVICE_RESTART_ON_SUCCESS] = "on-success",
diff --git a/src/core/service.h b/src/core/service.h
index 7da0a93961..e765668247 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -29,27 +29,6 @@ typedef struct ServiceFDStore ServiceFDStore;
#include "kill.h"
#include "exit-status.h"
-typedef enum ServiceState {
- SERVICE_DEAD,
- SERVICE_START_PRE,
- SERVICE_START,
- SERVICE_START_POST,
- SERVICE_RUNNING,
- SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
- SERVICE_RELOAD,
- SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
- SERVICE_STOP_SIGABRT, /* Watchdog timeout */
- SERVICE_STOP_SIGTERM,
- SERVICE_STOP_SIGKILL,
- SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
- SERVICE_FINAL_SIGKILL,
- SERVICE_FAILED,
- SERVICE_AUTO_RESTART,
- _SERVICE_STATE_MAX,
- _SERVICE_STATE_INVALID = -1
-} ServiceState;
-
typedef enum ServiceRestart {
SERVICE_RESTART_NO,
SERVICE_RESTART_ON_SUCCESS,
@@ -118,6 +97,7 @@ struct ServiceFDStore {
Service *service;
int fd;
+ char *fdname;
sd_event_source *event_source;
LIST_FIELDS(ServiceFDStore, fd_store);
@@ -212,15 +192,19 @@ struct Service {
ServiceFDStore *fd_store;
unsigned n_fd_store;
unsigned n_fd_store_max;
+
+ char *usb_function_descriptors;
+ char *usb_function_strings;
+
+ int stdin_fd;
+ int stdout_fd;
+ int stderr_fd;
};
extern const UnitVTable service_vtable;
int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net);
-const char* service_state_to_string(ServiceState i) _const_;
-ServiceState service_state_from_string(const char *s) _pure_;
-
const char* service_restart_to_string(ServiceRestart i) _const_;
ServiceRestart service_restart_from_string(const char *s) _pure_;
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 8cc6efc5b8..27c581d9c1 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -48,6 +48,7 @@
#define FINALIZE_ATTEMPTS 50
static char* arg_verb;
+static uint8_t arg_exit_code;
static int parse_argv(int argc, char *argv[]) {
enum {
@@ -55,6 +56,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_LOG_TARGET,
ARG_LOG_COLOR,
ARG_LOG_LOCATION,
+ ARG_EXIT_CODE,
};
static const struct option options[] = {
@@ -62,6 +64,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "log-target", required_argument, NULL, ARG_LOG_TARGET },
{ "log-color", optional_argument, NULL, ARG_LOG_COLOR },
{ "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
+ { "exit-code", required_argument, NULL, ARG_EXIT_CODE },
{}
};
@@ -110,6 +113,13 @@ static int parse_argv(int argc, char *argv[]) {
break;
+ case ARG_EXIT_CODE:
+ r = safe_atou8(optarg, &arg_exit_code);
+ if (r < 0)
+ log_error("Failed to parse exit code %s, ignoring", optarg);
+
+ break;
+
case '\001':
if (!arg_verb)
arg_verb = optarg;
@@ -183,6 +193,8 @@ int main(int argc, char *argv[]) {
cmd = RB_HALT_SYSTEM;
else if (streq(arg_verb, "kexec"))
cmd = LINUX_REBOOT_CMD_KEXEC;
+ else if (streq(arg_verb, "exit"))
+ cmd = 0; /* ignored, just checking that arg_verb is valid */
else {
r = -EINVAL;
log_error("Unknown action '%s'.", arg_verb);
@@ -339,6 +351,16 @@ int main(int argc, char *argv[]) {
if (!in_container)
sync();
+ if (streq(arg_verb, "exit")) {
+ if (in_container)
+ exit(arg_exit_code);
+ else {
+ /* We cannot exit() on the host, fallback on another
+ * method. */
+ cmd = RB_POWER_OFF;
+ }
+ }
+
switch (cmd) {
case LINUX_REBOOT_CMD_KEXEC:
@@ -408,6 +430,5 @@ int main(int argc, char *argv[]) {
error:
log_emergency_errno(r, "Critical error while doing system shutdown: %m");
-
freeze();
}
diff --git a/src/core/slice.c b/src/core/slice.c
index b414462066..1542e83eb6 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -274,6 +274,9 @@ static int slice_enumerate(Manager *m) {
u->default_dependencies = false;
u->no_gc = true;
+ u->ignore_on_isolate = true;
+ u->refuse_manual_start = true;
+ u->refuse_manual_stop = true;
SLICE(u)->deserialized_state = SLICE_ACTIVE;
if (!u->description)
@@ -287,13 +290,6 @@ static int slice_enumerate(Manager *m) {
return 0;
}
-static const char* const slice_state_table[_SLICE_STATE_MAX] = {
- [SLICE_DEAD] = "dead",
- [SLICE_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
-
const UnitVTable slice_vtable = {
.object_size = sizeof(Slice),
.cgroup_context_offset = offsetof(Slice, cgroup_context),
diff --git a/src/core/slice.h b/src/core/slice.h
index ac648e56f8..0c356651e3 100644
--- a/src/core/slice.h
+++ b/src/core/slice.h
@@ -23,14 +23,6 @@
typedef struct Slice Slice;
-
-typedef enum SliceState {
- SLICE_DEAD,
- SLICE_ACTIVE,
- _SLICE_STATE_MAX,
- _SLICE_STATE_INVALID = -1
-} SliceState;
-
struct Slice {
Unit meta;
@@ -40,6 +32,3 @@ struct Slice {
};
extern const UnitVTable slice_vtable;
-
-const char* slice_state_to_string(SliceState i) _const_;
-SliceState slice_state_from_string(const char *s) _pure_;
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index cbe7d0b4a9..761582c7a2 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -215,16 +215,14 @@ int mac_smack_setup(bool *loaded_policy) {
log_info("Successfully loaded Smack policies.");
break;
default:
- log_warning("Failed to load Smack access rules: %s, ignoring.",
- strerror(abs(r)));
+ log_warning_errno(r, "Failed to load Smack access rules, ignoring: %m");
return 0;
}
#ifdef SMACK_RUN_LABEL
r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0);
if (r)
- log_warning("Failed to set SMACK label \"%s\" on self: %s",
- SMACK_RUN_LABEL, strerror(-r));
+ log_warning_errno(r, "Failed to set SMACK label \"%s\" on self: %m", SMACK_RUN_LABEL);
#endif
r = write_cipso2_rules("/etc/smack/cipso.d/");
@@ -239,8 +237,7 @@ int mac_smack_setup(bool *loaded_policy) {
log_info("Successfully loaded Smack/CIPSO policies.");
break;
default:
- log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.",
- strerror(abs(r)));
+ log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m");
return 0;
}
diff --git a/src/core/snapshot.c b/src/core/snapshot.c
index 336ff20f84..867f3765e7 100644
--- a/src/core/snapshot.c
+++ b/src/core/snapshot.c
@@ -272,13 +272,6 @@ void snapshot_remove(Snapshot *s) {
unit_add_to_cleanup_queue(UNIT(s));
}
-static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
- [SNAPSHOT_DEAD] = "dead",
- [SNAPSHOT_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
-
const UnitVTable snapshot_vtable = {
.object_size = sizeof(Snapshot),
diff --git a/src/core/snapshot.h b/src/core/snapshot.h
index f2451b1193..97747e18bd 100644
--- a/src/core/snapshot.h
+++ b/src/core/snapshot.h
@@ -23,14 +23,6 @@
typedef struct Snapshot Snapshot;
-
-typedef enum SnapshotState {
- SNAPSHOT_DEAD,
- SNAPSHOT_ACTIVE,
- _SNAPSHOT_STATE_MAX,
- _SNAPSHOT_STATE_INVALID = -1
-} SnapshotState;
-
struct Snapshot {
Unit meta;
@@ -43,6 +35,3 @@ extern const UnitVTable snapshot_vtable;
int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s);
void snapshot_remove(Snapshot *s);
-
-const char* snapshot_state_to_string(SnapshotState i) _const_;
-SnapshotState snapshot_state_from_string(const char *s) _pure_;
diff --git a/src/core/socket.c b/src/core/socket.c
index 9db42a0333..e42ed62ef1 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -19,37 +19,39 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/stat.h>
-#include <unistd.h>
+#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
-#include <sys/epoll.h>
-#include <signal.h>
-#include <arpa/inet.h>
-#include <netinet/tcp.h>
#include <mqueue.h>
+#include <netinet/tcp.h>
+#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include "sd-event.h"
+
+#include "bus-error.h"
+#include "bus-util.h"
+#include "copy.h"
+#include "dbus-socket.h"
+#include "def.h"
+#include "exit-status.h"
+#include "formats-util.h"
+#include "label.h"
#include "log.h"
-#include "strv.h"
+#include "missing.h"
#include "mkdir.h"
#include "path-util.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "missing.h"
-#include "special.h"
-#include "label.h"
-#include "exit-status.h"
-#include "def.h"
-#include "smack-util.h"
-#include "bus-util.h"
-#include "bus-error.h"
#include "selinux-util.h"
-#include "dbus-socket.h"
-#include "unit.h"
-#include "formats-util.h"
#include "signal-util.h"
+#include "smack-util.h"
#include "socket.h"
+#include "special.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
@@ -104,6 +106,16 @@ static void socket_unwatch_control_pid(Socket *s) {
s->control_pid = 0;
}
+static void socket_cleanup_fd_list(SocketPort *p) {
+ int k = p->n_auxiliary_fds;
+
+ while (k--)
+ safe_close(p->auxiliary_fds[k]);
+
+ p->auxiliary_fds = mfree(p->auxiliary_fds);
+ p->n_auxiliary_fds = 0;
+}
+
void socket_free_ports(Socket *s) {
SocketPort *p;
@@ -114,6 +126,7 @@ void socket_free_ports(Socket *s) {
sd_event_source_unref(p->event_source);
+ socket_cleanup_fd_list(p);
safe_close(p->fd);
free(p->path);
free(p);
@@ -248,7 +261,7 @@ static int socket_add_mount_links(Socket *s) {
if (p->type == SOCKET_SOCKET)
path = socket_address_get_path(&p->address);
- else if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL)
+ else if (IN_SET(p->type, SOCKET_FIFO, SOCKET_SPECIAL, SOCKET_USB_FUNCTION))
path = p->path;
if (!path)
@@ -494,6 +507,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
"%sPassSecurity: %s\n"
"%sTCPCongestion: %s\n"
"%sRemoveOnStop: %s\n"
+ "%sWritable: %s\n"
+ "%sFDName: %s\n"
"%sSELinuxContextFromNet: %s\n",
prefix, socket_state_to_string(s->state),
prefix, socket_result_to_string(s->result),
@@ -510,6 +525,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
prefix, yes_no(s->pass_sec),
prefix, strna(s->tcp_congestion),
prefix, yes_no(s->remove_on_stop),
+ prefix, yes_no(s->writable),
+ prefix, socket_fdname(s),
prefix, yes_no(s->selinux_context_from_net));
if (s->control_pid > 0)
@@ -630,7 +647,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
int r;
char *k = NULL;
- if ((r = socket_address_print(&p->address, &k)) < 0)
+ r = socket_address_print(&p->address, &k);
+ if (r < 0)
t = strerror(-r);
else
t = k;
@@ -639,6 +657,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
free(k);
} else if (p->type == SOCKET_SPECIAL)
fprintf(f, "%sListenSpecial: %s\n", prefix, p->path);
+ else if (p->type == SOCKET_USB_FUNCTION)
+ fprintf(f, "%sListenUSBFunction: %s\n", prefix, p->path);
else if (p->type == SOCKET_MQUEUE)
fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path);
else
@@ -775,6 +795,7 @@ static void socket_close_fds(Socket *s) {
continue;
p->fd = safe_close(p->fd);
+ socket_cleanup_fd_list(p);
/* One little note: we should normally not delete any
* sockets in the file system here! After all some
@@ -940,50 +961,48 @@ static void socket_apply_fifo_options(Socket *s, int fd) {
if (s->pipe_size > 0)
if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
- log_unit_warning_errno(UNIT(s), errno, "F_SETPIPE_SZ: %m");
+ log_unit_warning_errno(UNIT(s), errno, "Setting pipe size failed, ignoring: %m");
if (s->smack) {
r = mac_smack_apply_fd(fd, SMACK_ATTR_ACCESS, s->smack);
if (r < 0)
- log_unit_error_errno(UNIT(s), r, "mac_smack_apply_fd: %m");
+ log_unit_error_errno(UNIT(s), r, "SMACK relabelling failed, ignoring: %m");
}
}
static int fifo_address_create(
const char *path,
mode_t directory_mode,
- mode_t socket_mode,
- int *_fd) {
+ mode_t socket_mode) {
- int fd = -1, r = 0;
- struct stat st;
+ _cleanup_close_ int fd = -1;
mode_t old_mask;
+ struct stat st;
+ int r;
assert(path);
- assert(_fd);
mkdir_parents_label(path, directory_mode);
r = mac_selinux_create_file_prepare(path, S_IFIFO);
if (r < 0)
- goto fail;
+ return r;
/* Enforce the right access mode for the fifo */
old_mask = umask(~ socket_mode);
/* Include the original umask in our mask */
- umask(~socket_mode | old_mask);
+ (void) umask(~socket_mode | old_mask);
r = mkfifo(path, socket_mode);
- umask(old_mask);
+ (void) umask(old_mask);
if (r < 0 && errno != EEXIST) {
r = -errno;
goto fail;
}
- fd = open(path,
- O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
+ fd = open(path, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
if (fd < 0) {
r = -errno;
goto fail;
@@ -1000,53 +1019,64 @@ static int fifo_address_create(
(st.st_mode & 0777) != (socket_mode & ~old_mask) ||
st.st_uid != getuid() ||
st.st_gid != getgid()) {
-
r = -EEXIST;
goto fail;
}
- *_fd = fd;
- return 0;
+ r = fd;
+ fd = -1;
+
+ return r;
fail:
mac_selinux_create_file_clear();
- safe_close(fd);
-
return r;
}
-static int special_address_create(
- const char *path,
- int *_fd) {
-
- int fd = -1, r = 0;
+static int special_address_create(const char *path, bool writable) {
+ _cleanup_close_ int fd = -1;
struct stat st;
+ int r;
assert(path);
- assert(_fd);
- fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
+ fd = open(path, (writable ? O_RDWR : O_RDONLY)|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
+ if (fstat(fd, &st) < 0)
+ return -errno;
/* Check whether this is a /proc, /sys or /dev file or char device */
- if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
- r = -EEXIST;
- goto fail;
- }
+ if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode))
+ return -EEXIST;
- *_fd = fd;
- return 0;
+ r = fd;
+ fd = -1;
-fail:
- safe_close(fd);
+ return r;
+}
+
+static int usbffs_address_create(const char *path) {
+ _cleanup_close_ int fd = -1;
+ struct stat st;
+ int r;
+
+ assert(path);
+
+ fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
+ if (fd < 0)
+ return -errno;
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ /* Check whether this is a regular file (ffs endpoint)*/
+ if (!S_ISREG(st.st_mode))
+ return -EEXIST;
+
+ r = fd;
+ fd = -1;
return r;
}
@@ -1055,22 +1085,22 @@ static int mq_address_create(
const char *path,
mode_t mq_mode,
long maxmsg,
- long msgsize,
- int *_fd) {
+ long msgsize) {
- int fd = -1, r = 0;
+ _cleanup_close_ int fd = -1;
struct stat st;
mode_t old_mask;
struct mq_attr _attr, *attr = NULL;
+ int r;
assert(path);
- assert(_fd);
if (maxmsg > 0 && msgsize > 0) {
- zero(_attr);
- _attr.mq_flags = O_NONBLOCK;
- _attr.mq_maxmsg = maxmsg;
- _attr.mq_msgsize = msgsize;
+ _attr = (struct mq_attr) {
+ .mq_flags = O_NONBLOCK,
+ .mq_maxmsg = maxmsg,
+ .mq_msgsize = msgsize,
+ };
attr = &_attr;
}
@@ -1078,33 +1108,24 @@ static int mq_address_create(
old_mask = umask(~ mq_mode);
/* Include the original umask in our mask */
- umask(~mq_mode | old_mask);
+ (void) umask(~mq_mode | old_mask);
fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
- umask(old_mask);
+ (void) umask(old_mask);
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
+ if (fd < 0)
+ return -errno;
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
+ if (fstat(fd, &st) < 0)
+ return -errno;
if ((st.st_mode & 0777) != (mq_mode & ~old_mask) ||
st.st_uid != getuid() ||
- st.st_gid != getgid()) {
+ st.st_gid != getgid())
+ return -EEXIST;
- r = -EEXIST;
- goto fail;
- }
+ r = fd;
+ fd = -1;
- *_fd = fd;
- return 0;
-
-fail:
- safe_close(fd);
return r;
}
@@ -1124,11 +1145,78 @@ static int socket_symlink(Socket *s) {
return 0;
}
+static int usbffs_write_descs(int fd, Service *s) {
+ int r;
+
+ if (!s->usb_function_descriptors || !s->usb_function_strings)
+ return -EINVAL;
+
+ r = copy_file_fd(s->usb_function_descriptors, fd, false);
+ if (r < 0)
+ return r;
+
+ return copy_file_fd(s->usb_function_strings, fd, false);
+}
+
+static int usbffs_select_ep(const struct dirent *d) {
+ return d->d_name[0] != '.' && !streq(d->d_name, "ep0");
+}
+
+static int usbffs_dispatch_eps(SocketPort *p) {
+ _cleanup_free_ struct dirent **ent = NULL;
+ _cleanup_free_ char *path = NULL;
+ int r, i, n, k;
+
+ r = path_get_parent(p->path, &path);
+ if (r < 0)
+ return r;
+
+ r = scandir(path, &ent, usbffs_select_ep, alphasort);
+ if (r < 0)
+ return -errno;
+
+ n = r;
+ p->auxiliary_fds = new(int, n);
+ if (!p->auxiliary_fds)
+ return -ENOMEM;
+
+ p->n_auxiliary_fds = n;
+
+ k = 0;
+ for (i = 0; i < n; ++i) {
+ _cleanup_free_ char *ep = NULL;
+
+ ep = path_make_absolute(ent[i]->d_name, path);
+ if (!ep)
+ return -ENOMEM;
+
+ path_kill_slashes(ep);
+
+ r = usbffs_address_create(ep);
+ if (r < 0)
+ goto fail;
+
+ p->auxiliary_fds[k] = r;
+
+ ++k;
+ free(ent[i]);
+ }
+
+ return r;
+
+fail:
+ close_many(p->auxiliary_fds, k);
+ p->auxiliary_fds = mfree(p->auxiliary_fds);
+ p->n_auxiliary_fds = 0;
+
+ return r;
+}
+
static int socket_open_fds(Socket *s) {
+ _cleanup_(mac_selinux_freep) char *label = NULL;
+ bool know_label = false;
SocketPort *p;
int r;
- char *label = NULL;
- bool know_label = false;
assert(s);
@@ -1137,7 +1225,9 @@ static int socket_open_fds(Socket *s) {
if (p->fd >= 0)
continue;
- if (p->type == SOCKET_SOCKET) {
+ switch (p->type) {
+
+ case SOCKET_SOCKET:
if (!know_label) {
/* Figure out label, if we don't it know
@@ -1188,49 +1278,72 @@ static int socket_open_fds(Socket *s) {
p->fd = r;
socket_apply_socket_options(s, p->fd);
socket_symlink(s);
+ break;
- } else if (p->type == SOCKET_SPECIAL) {
+ case SOCKET_SPECIAL:
- r = special_address_create(
- p->path,
- &p->fd);
- if (r < 0)
+ p->fd = special_address_create(p->path, s->writable);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
+ }
+ break;
- } else if (p->type == SOCKET_FIFO) {
+ case SOCKET_FIFO:
- r = fifo_address_create(
+ p->fd = fifo_address_create(
p->path,
s->directory_mode,
- s->socket_mode,
- &p->fd);
- if (r < 0)
+ s->socket_mode);
+ if (p->fd < 0) {
+ r = p->fd;
goto rollback;
+ }
socket_apply_fifo_options(s, p->fd);
socket_symlink(s);
+ break;
- } else if (p->type == SOCKET_MQUEUE) {
+ case SOCKET_MQUEUE:
- r = mq_address_create(
+ p->fd = mq_address_create(
p->path,
s->socket_mode,
s->mq_maxmsg,
- s->mq_msgsize,
- &p->fd);
+ s->mq_msgsize);
+ if (p->fd < 0) {
+ r = p->fd;
+ goto rollback;
+ }
+ break;
+
+ case SOCKET_USB_FUNCTION:
+
+ p->fd = usbffs_address_create(p->path);
+ if (p->fd < 0) {
+ r = p->fd;
+ goto rollback;
+ }
+
+ r = usbffs_write_descs(p->fd, SERVICE(UNIT_DEREF(s->service)));
if (r < 0)
goto rollback;
- } else
+
+ r = usbffs_dispatch_eps(p);
+ if (r < 0)
+ goto rollback;
+
+ break;
+
+ default:
assert_not_reached("Unknown port type");
+ }
}
- mac_selinux_free(label);
return 0;
rollback:
socket_close_fds(s);
- mac_selinux_free(label);
-
return r;
}
@@ -1392,6 +1505,9 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(s);
@@ -2035,6 +2151,8 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path);
else if (p->type == SOCKET_MQUEUE)
unit_serialize_item_format(u, f, "mqueue", "%i %s", copy, p->path);
+ else if (p->type == SOCKET_USB_FUNCTION)
+ unit_serialize_item_format(u, f, "ffs", "%i %s", copy, p->path);
else {
assert(p->type == SOCKET_FIFO);
unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path);
@@ -2184,6 +2302,26 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
p->fd = fdset_remove(fds, fd);
}
}
+
+ } else if (streq(key, "ffs")) {
+ int fd, skip = 0;
+ SocketPort *p;
+
+ if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse ffs value: %s", value);
+ else {
+
+ LIST_FOREACH(port, p, s->ports)
+ if (p->type == SOCKET_USB_FUNCTION &&
+ path_equal_or_files_same(p->path, value+skip))
+ break;
+
+ if (p) {
+ safe_close(p->fd);
+ p->fd = fdset_remove(fds, fd);
+ }
+ }
+
} else
log_unit_debug(UNIT(s), "Unknown serialization key: %s", key);
@@ -2266,6 +2404,9 @@ const char* socket_port_type_to_string(SocketPort *p) {
case SOCKET_FIFO:
return "FIFO";
+ case SOCKET_USB_FUNCTION:
+ return "USBFunction";
+
default:
return NULL;
}
@@ -2297,7 +2438,6 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
log_unit_error(UNIT(p->socket), "Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.");
else
log_unit_error(UNIT(p->socket), "Got unexpected poll event (0x%x) on socket.", revents);
-
goto fail;
}
@@ -2493,43 +2633,43 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use
return 0;
}
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
- int *rfds;
- unsigned rn_fds, k;
+int socket_collect_fds(Socket *s, int **fds) {
+ int *rfds, k = 0, n = 0;
SocketPort *p;
assert(s);
assert(fds);
- assert(n_fds);
/* Called from the service code for requesting our fds */
- rn_fds = 0;
- LIST_FOREACH(port, p, s->ports)
+ LIST_FOREACH(port, p, s->ports) {
if (p->fd >= 0)
- rn_fds++;
+ n++;
+ n += p->n_auxiliary_fds;
+ }
- if (rn_fds <= 0) {
+ if (n <= 0) {
*fds = NULL;
- *n_fds = 0;
return 0;
}
- rfds = new(int, rn_fds);
+ rfds = new(int, n);
if (!rfds)
return -ENOMEM;
- k = 0;
- LIST_FOREACH(port, p, s->ports)
+ LIST_FOREACH(port, p, s->ports) {
+ int i;
+
if (p->fd >= 0)
rfds[k++] = p->fd;
+ for (i = 0; i < p->n_auxiliary_fds; ++i)
+ rfds[k++] = p->auxiliary_fds[i];
+ }
- assert(k == rn_fds);
+ assert(k == n);
*fds = rfds;
- *n_fds = rn_fds;
-
- return 0;
+ return n;
}
static void socket_reset_failed(Unit *u) {
@@ -2625,23 +2765,18 @@ static int socket_get_timeout(Unit *u, uint64_t *timeout) {
return 1;
}
-static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
- [SOCKET_DEAD] = "dead",
- [SOCKET_START_PRE] = "start-pre",
- [SOCKET_START_CHOWN] = "start-chown",
- [SOCKET_START_POST] = "start-post",
- [SOCKET_LISTENING] = "listening",
- [SOCKET_RUNNING] = "running",
- [SOCKET_STOP_PRE] = "stop-pre",
- [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
- [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
- [SOCKET_STOP_POST] = "stop-post",
- [SOCKET_FINAL_SIGTERM] = "final-sigterm",
- [SOCKET_FINAL_SIGKILL] = "final-sigkill",
- [SOCKET_FAILED] = "failed"
-};
+char *socket_fdname(Socket *s) {
+ assert(s);
-DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
+ /* Returns the name to use for $LISTEN_NAMES. If the user
+ * didn't specify anything specifically, use the socket unit's
+ * name as fallback. */
+
+ if (s->fdname)
+ return s->fdname;
+
+ return UNIT(s)->id;
+}
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
[SOCKET_EXEC_START_PRE] = "StartPre",
diff --git a/src/core/socket.h b/src/core/socket.h
index fa3ebdafa0..94cda8a90d 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -27,24 +27,6 @@ typedef struct Socket Socket;
#include "mount.h"
#include "service.h"
-typedef enum SocketState {
- SOCKET_DEAD,
- SOCKET_START_PRE,
- SOCKET_START_CHOWN,
- SOCKET_START_POST,
- SOCKET_LISTENING,
- SOCKET_RUNNING,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL,
- SOCKET_STOP_POST,
- SOCKET_FINAL_SIGTERM,
- SOCKET_FINAL_SIGKILL,
- SOCKET_FAILED,
- _SOCKET_STATE_MAX,
- _SOCKET_STATE_INVALID = -1
-} SocketState;
-
typedef enum SocketExecCommand {
SOCKET_EXEC_START_PRE,
SOCKET_EXEC_START_CHOWN,
@@ -60,6 +42,7 @@ typedef enum SocketType {
SOCKET_FIFO,
SOCKET_SPECIAL,
SOCKET_MQUEUE,
+ SOCKET_USB_FUNCTION,
_SOCKET_FIFO_MAX,
_SOCKET_FIFO_INVALID = -1
} SocketType;
@@ -81,6 +64,8 @@ typedef struct SocketPort {
SocketType type;
int fd;
+ int *auxiliary_fds;
+ int n_auxiliary_fds;
SocketAddress address;
char *path;
@@ -133,6 +118,7 @@ struct Socket {
bool accept;
bool remove_on_stop;
+ bool writable;
/* Socket options */
bool keep_alive;
@@ -168,20 +154,23 @@ struct Socket {
char *user, *group;
bool reset_cpu_usage:1;
+
+ char *fdname;
};
/* Called from the service code when collecting fds */
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
+int socket_collect_fds(Socket *s, int **fds);
/* Called from the service code when a per-connection service ended */
void socket_connection_unref(Socket *s);
void socket_free_ports(Socket *s);
-extern const UnitVTable socket_vtable;
+int socket_instantiate_service(Socket *s);
-const char* socket_state_to_string(SocketState i) _const_;
-SocketState socket_state_from_string(const char *s) _pure_;
+char *socket_fdname(Socket *s);
+
+extern const UnitVTable socket_vtable;
const char* socket_exec_command_to_string(SocketExecCommand i) _const_;
SocketExecCommand socket_exec_command_from_string(const char *s) _pure_;
@@ -190,5 +179,3 @@ const char* socket_result_to_string(SocketResult i) _const_;
SocketResult socket_result_from_string(const char *s) _pure_;
const char* socket_port_type_to_string(SocketPort *p) _pure_;
-
-int socket_instantiate_service(Socket *s);
diff --git a/src/core/swap.c b/src/core/swap.c
index bef457069f..f42d151075 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -597,6 +597,9 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(s);
@@ -1398,21 +1401,6 @@ static bool swap_supported(void) {
return supported;
}
-static const char* const swap_state_table[_SWAP_STATE_MAX] = {
- [SWAP_DEAD] = "dead",
- [SWAP_ACTIVATING] = "activating",
- [SWAP_ACTIVATING_DONE] = "activating-done",
- [SWAP_ACTIVE] = "active",
- [SWAP_DEACTIVATING] = "deactivating",
- [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
- [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
- [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
- [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
- [SWAP_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
-
static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
[SWAP_EXEC_ACTIVATE] = "ExecActivate",
[SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
diff --git a/src/core/swap.h b/src/core/swap.h
index 9136b9abab..7f29603c32 100644
--- a/src/core/swap.h
+++ b/src/core/swap.h
@@ -26,22 +26,6 @@
typedef struct Swap Swap;
-
-typedef enum SwapState {
- SWAP_DEAD,
- SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */
- SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */
- SWAP_ACTIVE,
- SWAP_DEACTIVATING,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL,
- SWAP_DEACTIVATING_SIGTERM,
- SWAP_DEACTIVATING_SIGKILL,
- SWAP_FAILED,
- _SWAP_STATE_MAX,
- _SWAP_STATE_INVALID = -1
-} SwapState;
-
typedef enum SwapExecCommand {
SWAP_EXEC_ACTIVATE,
SWAP_EXEC_DEACTIVATE,
@@ -120,9 +104,6 @@ extern const UnitVTable swap_vtable;
int swap_process_device_new(Manager *m, struct udev_device *dev);
int swap_process_device_remove(Manager *m, struct udev_device *dev);
-const char* swap_state_to_string(SwapState i) _const_;
-SwapState swap_state_from_string(const char *s) _pure_;
-
const char* swap_exec_command_to_string(SwapExecCommand i) _const_;
SwapExecCommand swap_exec_command_from_string(const char *s) _pure_;
diff --git a/src/core/system.conf b/src/core/system.conf
index 231609033b..50668e12c4 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -17,9 +17,10 @@
#LogColor=yes
#LogLocation=no
#DumpCore=yes
-#CrashShell=no
#ShowStatus=yes
-#CrashChVT=1
+#CrashChangeVT=no
+#CrashShell=no
+#CrashReboot=no
#CPUAffinity=1 2
#JoinControllers=cpu,cpuacct net_cls,net_prio
#RuntimeWatchdogSec=0
@@ -39,6 +40,7 @@
#DefaultCPUAccounting=no
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting=no
+#DefaultTasksAccounting=no
#DefaultLimitCPU=
#DefaultLimitFSIZE=
#DefaultLimitDATA=
diff --git a/src/core/target.c b/src/core/target.c
index f714cb31c2..a905a1adf6 100644
--- a/src/core/target.c
+++ b/src/core/target.c
@@ -192,13 +192,6 @@ _pure_ static const char *target_sub_state_to_string(Unit *u) {
return target_state_to_string(TARGET(u)->state);
}
-static const char* const target_state_table[_TARGET_STATE_MAX] = {
- [TARGET_DEAD] = "dead",
- [TARGET_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
-
const UnitVTable target_vtable = {
.object_size = sizeof(Target),
diff --git a/src/core/target.h b/src/core/target.h
index 0a25ef469a..3cc6c07bfa 100644
--- a/src/core/target.h
+++ b/src/core/target.h
@@ -23,14 +23,6 @@
typedef struct Target Target;
-
-typedef enum TargetState {
- TARGET_DEAD,
- TARGET_ACTIVE,
- _TARGET_STATE_MAX,
- _TARGET_STATE_INVALID = -1
-} TargetState;
-
struct Target {
Unit meta;
@@ -38,6 +30,3 @@ struct Target {
};
extern const UnitVTable target_vtable;
-
-const char* target_state_to_string(TargetState i) _const_;
-TargetState target_state_from_string(const char *s) _pure_;
diff --git a/src/core/timer.c b/src/core/timer.c
index eb6567bbfa..800e58261c 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -713,16 +713,6 @@ static void timer_time_change(Unit *u) {
timer_enter_waiting(t, false);
}
-static const char* const timer_state_table[_TIMER_STATE_MAX] = {
- [TIMER_DEAD] = "dead",
- [TIMER_WAITING] = "waiting",
- [TIMER_RUNNING] = "running",
- [TIMER_ELAPSED] = "elapsed",
- [TIMER_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
-
static const char* const timer_base_table[_TIMER_BASE_MAX] = {
[TIMER_ACTIVE] = "OnActiveSec",
[TIMER_BOOT] = "OnBootSec",
diff --git a/src/core/timer.h b/src/core/timer.h
index 9d919e4d3e..ac5af6a93c 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -25,16 +25,6 @@ typedef struct Timer Timer;
#include "calendarspec.h"
-typedef enum TimerState {
- TIMER_DEAD,
- TIMER_WAITING,
- TIMER_RUNNING,
- TIMER_ELAPSED,
- TIMER_FAILED,
- _TIMER_STATE_MAX,
- _TIMER_STATE_INVALID = -1
-} TimerState;
-
typedef enum TimerBase {
TIMER_ACTIVE,
TIMER_BOOT,
@@ -91,9 +81,6 @@ void timer_free_values(Timer *t);
extern const UnitVTable timer_vtable;
-const char *timer_state_to_string(TimerState i) _const_;
-TimerState timer_state_from_string(const char *s) _pure_;
-
const char *timer_base_to_string(TimerBase i) _const_;
TimerBase timer_base_from_string(const char *s) _pure_;
diff --git a/src/core/transaction.c b/src/core/transaction.c
index b8f69ec6f3..d1c1b9a3cd 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -401,7 +401,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
"Job %s/%s deleted to break ordering cycle starting with %s/%s",
delete->unit->id, job_type_to_string(delete->type),
j->unit->id, job_type_to_string(j->type));
- unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF,
+ unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL,
"Ordering cycle found, skipping %s");
transaction_delete_unit(tr, delete->unit);
return -EAGAIN;
@@ -736,8 +736,8 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error
if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
- pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
- pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
+ (void) pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
+ (void) pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
}
}
diff --git a/src/core/unit.c b/src/core/unit.c
index e40ea24be8..39cd89f1e3 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -125,6 +125,7 @@ static void unit_init(Unit *u) {
cc->cpu_accounting = u->manager->default_cpu_accounting;
cc->blockio_accounting = u->manager->default_blockio_accounting;
cc->memory_accounting = u->manager->default_memory_accounting;
+ cc->tasks_accounting = u->manager->default_tasks_accounting;
}
ec = unit_get_exec_context(u);
@@ -451,6 +452,7 @@ static void unit_free_requires_mounts_for(Unit *u) {
static void unit_done(Unit *u) {
ExecContext *ec;
CGroupContext *cc;
+ int r;
assert(u);
@@ -467,6 +469,10 @@ static void unit_done(Unit *u) {
cc = unit_get_cgroup_context(u);
if (cc)
cgroup_context_done(cc);
+
+ r = unit_remove_from_netclass_cgroup(u);
+ if (r < 0)
+ log_warning_errno(r, "Unable to remove unit from netclass group: %m");
}
void unit_free(Unit *u) {
@@ -527,7 +533,7 @@ void unit_free(Unit *u) {
unit_release_cgroup(u);
- manager_update_failed_units(u->manager, u, false);
+ (void) manager_update_failed_units(u->manager, u, false);
set_remove(u->manager->startup_units, u);
free(u->description);
@@ -1123,12 +1129,12 @@ static int unit_add_slice_dependencies(Unit *u) {
return 0;
if (UNIT_ISSET(u->slice))
- return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true);
+ return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true);
- if (streq(u->id, SPECIAL_ROOT_SLICE))
+ if (unit_has_name(u, SPECIAL_ROOT_SLICE))
return 0;
- return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, SPECIAL_ROOT_SLICE, NULL, true);
+ return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true);
}
static int unit_add_mount_dependencies(Unit *u) {
@@ -1141,13 +1147,23 @@ static int unit_add_mount_dependencies(Unit *u) {
char prefix[strlen(*i) + 1];
PATH_FOREACH_PREFIX_MORE(prefix, *i) {
+ _cleanup_free_ char *p = NULL;
Unit *m;
- r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m);
+ r = unit_name_from_path(prefix, ".mount", &p);
if (r < 0)
return r;
- if (r == 0)
+
+ m = manager_get_unit(u->manager, p);
+ if (!m) {
+ /* Make sure to load the mount unit if
+ * it exists. If so the dependencies
+ * on this unit will be added later
+ * during the loading of the mount
+ * unit. */
+ (void) manager_load_unit_prepare(u->manager, p, NULL, NULL, &m);
continue;
+ }
if (m == u)
continue;
@@ -1171,15 +1187,20 @@ static int unit_add_mount_dependencies(Unit *u) {
static int unit_add_startup_units(Unit *u) {
CGroupContext *c;
+ int r;
c = unit_get_cgroup_context(u);
if (!c)
return 0;
- if (c->startup_cpu_shares == (unsigned long) -1 &&
- c->startup_blockio_weight == (unsigned long) -1)
+ if (c->startup_cpu_shares == CGROUP_CPU_SHARES_INVALID &&
+ c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID)
return 0;
+ r = set_ensure_allocated(&u->manager->startup_units, NULL);
+ if (r < 0)
+ return r;
+
return set_put(u->manager->startup_units, u);
}
@@ -1235,6 +1256,14 @@ int unit_load(Unit *u) {
}
unit_update_cgroup_members_masks(u);
+
+ /* If we are reloading, we need to wait for the deserializer
+ * to restore the net_cls ids that have been set previously */
+ if (u->manager->n_reloading <= 0) {
+ r = unit_add_to_netclass_cgroup(u);
+ if (r < 0)
+ return r;
+ }
}
assert((u->load_state != UNIT_MERGED) == !u->merged_into);
@@ -1806,7 +1835,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
}
/* Keep track of failed units */
- manager_update_failed_units(u->manager, u, ns == UNIT_FAILED);
+ (void) manager_update_failed_units(u->manager, u, ns == UNIT_FAILED);
/* Make sure the cgroup is always removed when we become inactive */
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
@@ -2585,6 +2614,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
unit_serialize_item(u, f, "cgroup", u->cgroup_path);
unit_serialize_item(u, f, "cgroup-realized", yes_no(u->cgroup_realized));
+ if (u->cgroup_netclass_id)
+ unit_serialize_item_format(u, f, "netclass-id", "%" PRIu32, u->cgroup_netclass_id);
+
if (serialize_jobs) {
if (u->job) {
fprintf(f, "job\n");
@@ -2602,6 +2634,62 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
return 0;
}
+int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
+ assert(u);
+ assert(f);
+ assert(key);
+
+ if (!value)
+ return 0;
+
+ fputs(key, f);
+ fputc('=', f);
+ fputs(value, f);
+ fputc('\n', f);
+
+ return 1;
+}
+
+int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value) {
+ _cleanup_free_ char *c = NULL;
+
+ assert(u);
+ assert(f);
+ assert(key);
+
+ if (!value)
+ return 0;
+
+ c = cescape(value);
+ if (!c)
+ return -ENOMEM;
+
+ fputs(key, f);
+ fputc('=', f);
+ fputs(c, f);
+ fputc('\n', f);
+
+ return 1;
+}
+
+int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd) {
+ int copy;
+
+ assert(u);
+ assert(f);
+ assert(key);
+
+ if (fd < 0)
+ return 0;
+
+ copy = fdset_put_dup(fds, fd);
+ if (copy < 0)
+ return copy;
+
+ fprintf(f, "%s=%i\n", key, copy);
+ return 1;
+}
+
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
va_list ap;
@@ -2620,15 +2708,6 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f
fputc('\n', f);
}
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
- assert(u);
- assert(f);
- assert(key);
- assert(value);
-
- fprintf(f, "%s=%s\n", key, value);
-}
-
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
ExecRuntime **rt = NULL;
size_t offset;
@@ -2772,6 +2851,17 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
u->cgroup_realized = b;
continue;
+ } else if (streq(l, "netclass-id")) {
+ r = safe_atou32(v, &u->cgroup_netclass_id);
+ if (r < 0)
+ log_unit_debug(u, "Failed to parse netclass ID %s, ignoring.", v);
+ else {
+ r = unit_add_to_netclass_cgroup(u);
+ if (r < 0)
+ log_unit_debug_errno(u, r, "Failed to add unit to netclass cgroup, ignoring: %m");
+ }
+
+ continue;
}
if (unit_can_serialize(u)) {
@@ -3031,32 +3121,39 @@ int unit_kill_common(
sd_bus_error *error) {
int r = 0;
+ bool killed = false;
- if (who == KILL_MAIN) {
+ if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL)) {
if (main_pid < 0)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
else if (main_pid == 0)
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
}
- if (who == KILL_CONTROL) {
+ if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL)) {
if (control_pid < 0)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
else if (control_pid == 0)
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
}
- if (who == KILL_CONTROL || who == KILL_ALL)
- if (control_pid > 0)
+ if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL, KILL_ALL, KILL_ALL_FAIL))
+ if (control_pid > 0) {
if (kill(control_pid, signo) < 0)
r = -errno;
+ else
+ killed = true;
+ }
- if (who == KILL_MAIN || who == KILL_ALL)
- if (main_pid > 0)
+ if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL, KILL_ALL, KILL_ALL_FAIL))
+ if (main_pid > 0) {
if (kill(main_pid, signo) < 0)
r = -errno;
+ else
+ killed = true;
+ }
- if (who == KILL_ALL && u->cgroup_path) {
+ if (IN_SET(who, KILL_ALL, KILL_ALL_FAIL) && u->cgroup_path) {
_cleanup_set_free_ Set *pid_set = NULL;
int q;
@@ -3068,8 +3165,13 @@ int unit_kill_common(
q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, false, false, pid_set);
if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
r = q;
+ else
+ killed = true;
}
+ if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_ALL_FAIL))
+ return -ESRCH;
+
return r;
}
@@ -3684,14 +3786,3 @@ int unit_fail_if_symlink(Unit *u, const char* where) {
return -ELOOP;
}
-
-static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
- [UNIT_ACTIVE] = "active",
- [UNIT_RELOADING] = "reloading",
- [UNIT_INACTIVE] = "inactive",
- [UNIT_FAILED] = "failed",
- [UNIT_ACTIVATING] = "activating",
- [UNIT_DEACTIVATING] = "deactivating"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
diff --git a/src/core/unit.h b/src/core/unit.h
index 3c7684411b..a4a1b011fc 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -27,7 +27,6 @@
typedef struct Unit Unit;
typedef struct UnitVTable UnitVTable;
-typedef enum UnitActiveState UnitActiveState;
typedef struct UnitRef UnitRef;
typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
@@ -37,17 +36,6 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
#include "unit-name.h"
#include "failure-action.h"
-enum UnitActiveState {
- UNIT_ACTIVE,
- UNIT_RELOADING,
- UNIT_INACTIVE,
- UNIT_FAILED,
- UNIT_ACTIVATING,
- UNIT_DEACTIVATING,
- _UNIT_ACTIVE_STATE_MAX,
- _UNIT_ACTIVE_STATE_INVALID = -1
-};
-
typedef enum KillOperation {
KILL_TERMINATE,
KILL_KILL,
@@ -161,6 +149,9 @@ struct Unit {
/* CGroup realize members queue */
LIST_FIELDS(Unit, cgroup_queue);
+ /* Units with the same CGroup netclass */
+ LIST_FIELDS(Unit, cgroup_netclass);
+
/* PIDs we keep an eye on. Note that a unit might have many
* more, but these are the ones we care enough about to
* process SIGCHLD for */
@@ -189,6 +180,8 @@ struct Unit {
CGroupMask cgroup_members_mask;
int cgroup_inotify_wd;
+ uint32_t cgroup_netclass_id;
+
/* How to start OnFailure units */
JobMode on_failure_job_mode;
@@ -540,11 +533,15 @@ char *unit_dbus_path(Unit *u);
int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
bool unit_can_serialize(Unit *u) _pure_;
+
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
+int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
+int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value);
+int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd);
+void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
+
int unit_add_node_link(Unit *u, const char *what, bool wants);
int unit_coldplug(Unit *u);
@@ -612,9 +609,6 @@ static inline bool unit_supported(Unit *u) {
void unit_warn_if_dir_nonempty(Unit *u, const char* where);
int unit_fail_if_symlink(Unit *u, const char* where);
-const char *unit_active_state_to_string(UnitActiveState i) _const_;
-UnitActiveState unit_active_state_from_string(const char *s) _pure_;
-
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 5d5872b7f4..cc03ad3ca8 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -313,14 +313,10 @@ static char *disk_mount_point(const char *label) {
}
static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***passwords) {
- int r = 0;
- char **p;
- _cleanup_free_ char *text = NULL;
- _cleanup_free_ char *escaped_name = NULL;
- char *id;
+ _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *maj_min = NULL, *text = NULL, *escaped_name = NULL;
const char *name = NULL;
- _cleanup_free_ char *description = NULL, *name_buffer = NULL,
- *mount_point = NULL, *maj_min = NULL;
+ char **p, *id;
+ int r = 0;
assert(vol);
assert(src);
@@ -364,7 +360,7 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
id = strjoina("cryptsetup:", escaped_name);
- r = ask_password_auto(text, "drive-harddisk", id, until, accept_cached, passwords);
+ r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE|(accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0), passwords);
if (r < 0)
return log_error_errno(r, "Failed to query password: %m");
@@ -378,7 +374,7 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc
id = strjoina("cryptsetup-verification:", escaped_name);
- r = ask_password_auto(text, "drive-harddisk", id, until, false, &passwords2);
+ r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
if (r < 0)
return log_error_errno(r, "Failed to query verification password: %m");
diff --git a/src/delta/delta.c b/src/delta/delta.c
index b60aaef734..4edafc7cdf 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -21,21 +21,20 @@
***/
#include <errno.h>
-#include <string.h>
-#include <unistd.h>
#include <getopt.h>
+#include <string.h>
#include <sys/prctl.h>
+#include <unistd.h>
#include "hashmap.h"
-#include "util.h"
-#include "path-util.h"
#include "log.h"
#include "pager.h"
-#include "build.h"
-#include "strv.h"
+#include "path-util.h"
#include "process-util.h"
-#include "terminal-util.h"
#include "signal-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "util.h"
static const char prefixes[] =
"/etc\0"
@@ -107,7 +106,7 @@ static int notify_override_masked(const char *top, const char *bottom) {
return 0;
printf("%s%s%s %s %s %s\n",
- ansi_highlight_red(), "[MASKED]", ansi_highlight_off(),
+ ansi_highlight_red(), "[MASKED]", ansi_normal(),
top, draw_special_char(DRAW_ARROW), bottom);
return 1;
}
@@ -117,7 +116,7 @@ static int notify_override_equivalent(const char *top, const char *bottom) {
return 0;
printf("%s%s%s %s %s %s\n",
- ansi_highlight_green(), "[EQUIVALENT]", ansi_highlight_off(),
+ ansi_highlight_green(), "[EQUIVALENT]", ansi_normal(),
top, draw_special_char(DRAW_ARROW), bottom);
return 1;
}
@@ -127,7 +126,7 @@ static int notify_override_redirected(const char *top, const char *bottom) {
return 0;
printf("%s%s%s %s %s %s\n",
- ansi_highlight(), "[REDIRECTED]", ansi_highlight_off(),
+ ansi_highlight(), "[REDIRECTED]", ansi_normal(),
top, draw_special_char(DRAW_ARROW), bottom);
return 1;
}
@@ -137,7 +136,7 @@ static int notify_override_overridden(const char *top, const char *bottom) {
return 0;
printf("%s%s%s %s %s %s\n",
- ansi_highlight(), "[OVERRIDDEN]", ansi_highlight_off(),
+ ansi_highlight(), "[OVERRIDDEN]", ansi_normal(),
top, draw_special_char(DRAW_ARROW), bottom);
return 1;
}
@@ -147,7 +146,7 @@ static int notify_override_extended(const char *top, const char *bottom) {
return 0;
printf("%s%s%s %s %s %s\n",
- ansi_highlight(), "[EXTENDED]", ansi_highlight_off(),
+ ansi_highlight(), "[EXTENDED]", ansi_normal(),
top, draw_special_char(DRAW_ARROW), bottom);
return 1;
}
@@ -544,9 +543,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c
index 97ae569ca5..dcf4e9749e 100644
--- a/src/detect-virt/detect-virt.c
+++ b/src/detect-virt/detect-virt.c
@@ -19,14 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
#include <getopt.h>
+#include <stdbool.h>
+#include <stdlib.h>
#include "util.h"
#include "virt.h"
-#include "build.h"
static bool arg_quiet = false;
static enum {
@@ -75,9 +74,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'q':
arg_quiet = true;
@@ -99,8 +96,7 @@ static int parse_argv(int argc, char *argv[]) {
}
if (optind < argc) {
- log_error("%s takes no arguments.",
- program_invocation_short_name);
+ log_error("%s takes no arguments.", program_invocation_short_name);
return -EINVAL;
}
@@ -108,7 +104,7 @@ static int parse_argv(int argc, char *argv[]) {
}
int main(int argc, char *argv[]) {
- int retval = EXIT_SUCCESS, r;
+ int r;
/* This is mostly intended to be used for scripts which want
* to detect whether we are being run in a virtualized
@@ -126,7 +122,7 @@ int main(int argc, char *argv[]) {
case ONLY_VM:
r = detect_vm();
if (r < 0) {
- log_error_errno(r, "Failed to check for vm: %m");
+ log_error_errno(r, "Failed to check for VM: %m");
return EXIT_FAILURE;
}
@@ -155,7 +151,5 @@ int main(int argc, char *argv[]) {
if (!arg_quiet)
puts(virtualization_to_string(r));
- retval = r != VIRTUALIZATION_NONE ? EXIT_SUCCESS : EXIT_FAILURE;
-
- return retval;
+ return r != VIRTUALIZATION_NONE ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/src/escape/escape.c b/src/escape/escape.c
index 341453398d..a4bfeb5df5 100644
--- a/src/escape/escape.c
+++ b/src/escape/escape.c
@@ -19,14 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
-#include <getopt.h>
#include "log.h"
-#include "unit-name.h"
-#include "build.h"
#include "strv.h"
+#include "unit-name.h"
static enum {
ACTION_ESCAPE,
@@ -83,9 +82,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_SUFFIX:
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index e2a1c00a75..1562ccf0d7 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -19,24 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
#include <fcntl.h>
-#include <unistd.h>
#include <getopt.h>
#include <shadow.h>
+#include <unistd.h>
-#include "strv.h"
-#include "fileio.h"
+#include "ask-password-api.h"
#include "copy.h"
-#include "build.h"
+#include "fileio.h"
+#include "hostname-util.h"
+#include "locale-util.h"
#include "mkdir.h"
-#include "time-util.h"
#include "path-util.h"
#include "random-util.h"
-#include "locale-util.h"
-#include "ask-password-api.h"
+#include "strv.h"
#include "terminal-util.h"
-#include "hostname-util.h"
+#include "time-util.h"
static char *arg_root = NULL;
static char *arg_locale = NULL; /* $LANG */
@@ -468,7 +466,7 @@ static int prompt_root_password(void) {
for (;;) {
_cleanup_free_ char *a = NULL, *b = NULL;
- r = ask_password_tty(msg1, 0, false, NULL, &a);
+ r = ask_password_tty(msg1, NULL, 0, 0, NULL, &a);
if (r < 0)
return log_error_errno(r, "Failed to query root password: %m");
@@ -477,11 +475,10 @@ static int prompt_root_password(void) {
break;
}
- r = ask_password_tty(msg2, 0, false, NULL, &b);
+ r = ask_password_tty(msg2, NULL, 0, 0, NULL, &b);
if (r < 0) {
- log_error_errno(r, "Failed to query root password: %m");
clear_string(a);
- return r;
+ return log_error_errno(r, "Failed to query root password: %m");
}
if (!streq(a, b)) {
@@ -704,9 +701,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ROOT:
free(arg_root);
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index bd3051f30d..30c846f01d 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -60,14 +60,14 @@ static bool arg_force = false;
static bool arg_show_progress = false;
static const char *arg_repair = "-a";
-static void start_target(const char *target) {
+static void start_target(const char *target, const char *mode) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
int r;
assert(target);
- r = bus_open_system_systemd(&bus);
+ r = bus_connect_system_systemd(&bus);
if (r < 0) {
log_error_errno(r, "Failed to get D-Bus connection: %m");
return;
@@ -83,7 +83,7 @@ static void start_target(const char *target) {
"StartUnitReplace",
&error,
NULL,
- "sss", "basic.target", target, "replace");
+ "sss", "basic.target", target, mode);
/* Don't print a warning if we aren't called during startup */
if (r < 0 && !sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_JOB))
@@ -463,10 +463,10 @@ int main(int argc, char *argv[]) {
if (status.si_code == CLD_EXITED && (status.si_status & FSCK_SYSTEM_SHOULD_REBOOT) && root_directory)
/* System should be rebooted. */
- start_target(SPECIAL_REBOOT_TARGET);
+ start_target(SPECIAL_REBOOT_TARGET, "replace-irreversibly");
else if (status.si_code == CLD_EXITED && (status.si_status & (FSCK_SYSTEM_SHOULD_REBOOT | FSCK_ERRORS_LEFT_UNCORRECTED)))
/* Some other problem */
- start_target(SPECIAL_EMERGENCY_TARGET);
+ start_target(SPECIAL_EMERGENCY_TARGET, "replace");
else {
log_warning("Ignoring error.");
r = 0;
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index bb821797f1..96425c5b07 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -38,6 +38,7 @@
#include "gpt.h"
#include "fileio.h"
#include "efivars.h"
+#include "fstab-util.h"
#include "blkid-util.h"
#include "btrfs-util.h"
@@ -465,6 +466,12 @@ static int add_boot(const char *what) {
return 0;
}
+ /* We create an .automount which is not overridden by the .mount from the fstab generator. */
+ if (fstab_is_mount_point("/boot")) {
+ log_debug("/boot specified in fstab, ignoring.");
+ return 0;
+ }
+
if (path_is_busy("/boot")) {
log_debug("/boot already populated, ignoring.");
return 0;
@@ -864,7 +871,6 @@ static int get_block_device_harder(const char *path, dev_t *dev) {
goto fallback;
found = de;
- break;
}
if (!found)
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index dcbad99ae9..0724fcc16d 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -19,21 +19,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <getopt.h>
#include <locale.h>
+#include <stdbool.h>
+#include <stdlib.h>
#include <string.h>
#include "sd-bus.h"
#include "sd-id128.h"
-#include "hostname-util.h"
-#include "bus-util.h"
+
+#include "architecture.h"
#include "bus-error.h"
-#include "util.h"
+#include "bus-util.h"
+#include "hostname-util.h"
#include "spawn-polkit-agent.h"
-#include "build.h"
-#include "architecture.h"
+#include "util.h"
static bool arg_ask_password = true;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
@@ -387,9 +387,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
@@ -519,7 +517,7 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index 96cc8951e6..dd508aefb5 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -709,12 +709,6 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (argc != 1) {
- log_error("This program takes no arguments.");
- r = -EINVAL;
- goto finish;
- }
-
r = sd_event_default(&event);
if (r < 0) {
log_error_errno(r, "Failed to allocate event loop: %m");
diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c
index 446de3a2fc..1e415db845 100644
--- a/src/hwdb/hwdb.c
+++ b/src/hwdb/hwdb.c
@@ -17,21 +17,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
+#include <ctype.h>
#include <getopt.h>
+#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include "util.h"
-#include "strbuf.h"
#include "conf-files.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "verbs.h"
-#include "build.h"
-
#include "hwdb-internal.h"
#include "hwdb-util.h"
+#include "mkdir.h"
+#include "strbuf.h"
+#include "strv.h"
+#include "util.h"
+#include "verbs.h"
/*
* Generic udev properties, key/value database based on modalias strings.
@@ -688,9 +686,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_USR:
arg_hwdb_bin_dir = UDEVLIBEXECDIR;
diff --git a/src/import/export.c b/src/import/export.c
index b88d71fec6..d34105e4ca 100644
--- a/src/import/export.c
+++ b/src/import/export.c
@@ -22,15 +22,15 @@
#include <getopt.h>
#include "sd-event.h"
+
#include "event-util.h"
-#include "signal-util.h"
+#include "export-raw.h"
+#include "export-tar.h"
#include "hostname-util.h"
-#include "verbs.h"
-#include "build.h"
-#include "machine-image.h"
#include "import-util.h"
-#include "export-tar.h"
-#include "export-raw.h"
+#include "machine-image.h"
+#include "signal-util.h"
+#include "verbs.h"
static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN;
@@ -260,9 +260,7 @@ static int parse_argv(int argc, char *argv[]) {
return help(0, NULL, NULL);
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_FORMAT:
if (streq(optarg, "uncompressed"))
diff --git a/src/import/import-common.c b/src/import/import-common.c
index d8a3bbc249..9b86dbfa79 100644
--- a/src/import/import-common.c
+++ b/src/import/import-common.c
@@ -19,14 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <sched.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <unistd.h>
-#include "util.h"
#include "btrfs-util.h"
#include "capability.h"
#include "signal-util.h"
+#include "util.h"
#include "import-common.h"
int import_make_read_only_fd(int fd) {
diff --git a/src/import/import.c b/src/import/import.c
index 929a840298..1c92312585 100644
--- a/src/import/import.c
+++ b/src/import/import.c
@@ -22,15 +22,15 @@
#include <getopt.h>
#include "sd-event.h"
+
#include "event-util.h"
-#include "verbs.h"
-#include "build.h"
-#include "signal-util.h"
#include "hostname-util.h"
-#include "machine-image.h"
-#include "import-util.h"
-#include "import-tar.h"
#include "import-raw.h"
+#include "import-tar.h"
+#include "import-util.h"
+#include "machine-image.h"
+#include "signal-util.h"
+#include "verbs.h"
static bool arg_force = false;
static bool arg_read_only = false;
@@ -280,9 +280,7 @@ static int parse_argv(int argc, char *argv[]) {
return help(0, NULL, NULL);
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_FORCE:
arg_force = true;
diff --git a/src/import/importd.c b/src/import/importd.c
index b91300a5df..a29e9d4bd5 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -167,6 +167,7 @@ static int transfer_new(Manager *m, Transfer **ret) {
t->type = _TRANSFER_TYPE_INVALID;
t->log_fd = -1;
t->stdin_fd = -1;
+ t->stdout_fd = -1;
t->verify = _IMPORT_VERIFY_INVALID;
id = m->current_transfer_id + 1;
@@ -599,11 +600,11 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
cmsg_close_all(&msghdr);
- CMSG_FOREACH(cmsg, &msghdr) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
-
+ CMSG_FOREACH(cmsg, &msghdr)
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
ucred = (struct ucred*) CMSG_DATA(cmsg);
- }
if (msghdr.msg_flags & MSG_TRUNC) {
log_warning("Got overly long notification datagram, ignoring.");
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index 38201e46e1..1ddb48e03f 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -31,8 +31,10 @@
#include "pull-common.h"
#include "process-util.h"
#include "signal-util.h"
+#include "siphash24.h"
#define FILENAME_ESCAPE "/.#\"\'"
+#define HASH_URL_THRESHOLD_LENGTH (_POSIX_PATH_MAX - 16)
int pull_find_old_etags(
const char *url,
@@ -149,8 +151,21 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
return 0;
}
+static int hash_url(const char *url, char **ret) {
+ uint64_t h;
+ static const sd_id128_t k = SD_ID128_ARRAY(df,89,16,87,01,cc,42,30,98,ab,4a,19,a6,a5,63,4f);
+
+ assert(url);
+
+ siphash24((uint8_t *) &h, url, strlen(url), k.bytes);
+ if (asprintf(ret, "%"PRIx64, h) < 0)
+ return -ENOMEM;
+
+ return 0;
+}
+
int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret) {
- _cleanup_free_ char *escaped_url = NULL;
+ _cleanup_free_ char *escaped_url = NULL, *escaped_etag = NULL;
char *path;
assert(url);
@@ -164,18 +179,35 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co
return -ENOMEM;
if (etag) {
- _cleanup_free_ char *escaped_etag = NULL;
-
escaped_etag = xescape(etag, FILENAME_ESCAPE);
if (!escaped_etag)
return -ENOMEM;
+ }
- path = strjoin(image_root, "/", strempty(prefix), escaped_url, ".", escaped_etag, strempty(suffix), NULL);
- } else
- path = strjoin(image_root, "/", strempty(prefix), escaped_url, strempty(suffix), NULL);
+ path = strjoin(image_root, "/", strempty(prefix), escaped_url, escaped_etag ? "." : "",
+ strempty(escaped_etag), strempty(suffix), NULL);
if (!path)
return -ENOMEM;
+ /* URLs might make the path longer than the maximum allowed length for a file name.
+ * When that happens, a URL hash is used instead. Paths returned by this function
+ * can be later used with tempfn_random() which adds 16 bytes to the resulting name. */
+ if (strlen(path) >= HASH_URL_THRESHOLD_LENGTH) {
+ _cleanup_free_ char *hash = NULL;
+ int r;
+
+ free(path);
+
+ r = hash_url(url, &hash);
+ if (r < 0)
+ return r;
+
+ path = strjoin(image_root, "/", strempty(prefix), hash, escaped_etag ? "." : "",
+ strempty(escaped_etag), strempty(suffix), NULL);
+ if (!path)
+ return -ENOMEM;
+ }
+
*ret = path;
return 0;
}
diff --git a/src/import/pull.c b/src/import/pull.c
index 98c22aeec9..29e9424b52 100644
--- a/src/import/pull.c
+++ b/src/import/pull.c
@@ -22,16 +22,16 @@
#include <getopt.h>
#include "sd-event.h"
+
#include "event-util.h"
-#include "verbs.h"
-#include "build.h"
-#include "signal-util.h"
#include "hostname-util.h"
-#include "machine-image.h"
#include "import-util.h"
-#include "pull-tar.h"
-#include "pull-raw.h"
+#include "machine-image.h"
#include "pull-dkr.h"
+#include "pull-raw.h"
+#include "pull-tar.h"
+#include "signal-util.h"
+#include "verbs.h"
static bool arg_force = false;
static const char *arg_image_root = "/var/lib/machines";
@@ -381,9 +381,7 @@ static int parse_argv(int argc, char *argv[]) {
return help(0, NULL, NULL);
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_FORCE:
arg_force = true;
diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c
index 6d08db74ef..2d5f7501e7 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -318,7 +318,7 @@ static int server_init(Server *s, unsigned n_sockets) {
s->n_fifos ++;
}
- r = bus_open_system_systemd(&s->bus);
+ r = bus_connect_system_systemd(&s->bus);
if (r < 0) {
log_error_errno(r, "Failed to get D-Bus connection: %m");
r = -EIO;
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 4e5572db0b..b839e5979b 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -24,9 +24,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
-
#include <microhttpd.h>
-
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
#endif
@@ -34,15 +32,15 @@
#include "sd-journal.h"
#include "sd-daemon.h"
#include "sd-bus.h"
-#include "log.h"
-#include "util.h"
+
#include "bus-util.h"
+#include "fileio.h"
+#include "hostname-util.h"
+#include "log.h"
#include "logs-show.h"
#include "microhttpd-util.h"
-#include "build.h"
-#include "fileio.h"
#include "sigbus.h"
-#include "hostname-util.h"
+#include "util.h"
static char *arg_key_pem = NULL;
static char *arg_cert_pem = NULL;
@@ -909,9 +907,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_KEY:
if (arg_key_pem) {
@@ -1014,7 +1010,22 @@ int main(int argc, char *argv[]) {
{ MHD_OPTION_END, 0, NULL },
{ MHD_OPTION_END, 0, NULL }};
int opts_pos = 2;
- int flags = MHD_USE_THREAD_PER_CONNECTION|MHD_USE_POLL|MHD_USE_DEBUG;
+
+ /* We force MHD_USE_PIPE_FOR_SHUTDOWN here, in order
+ * to make sure libmicrohttpd doesn't use shutdown()
+ * on our listening socket, which would break socket
+ * re-activation. See
+ *
+ * https://lists.gnu.org/archive/html/libmicrohttpd/2015-09/msg00014.html
+ * https://github.com/systemd/systemd/pull/1286
+ */
+
+ int flags =
+ MHD_USE_DEBUG |
+ MHD_USE_DUAL_STACK |
+ MHD_USE_PIPE_FOR_SHUTDOWN |
+ MHD_USE_POLL |
+ MHD_USE_THREAD_PER_CONNECTION;
if (n > 0)
opts[opts_pos++] = (struct MHD_OptionItem)
diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c
index d6ebca20ec..c920ef7626 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/journal-remote/journal-remote.c
@@ -21,31 +21,30 @@
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <unistd.h>
-#include <getopt.h>
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
#include "sd-daemon.h"
-#include "signal-util.h"
+
+#include "conf-parser.h"
+#include "fileio.h"
#include "journal-file.h"
#include "journald-native.h"
-#include "socket-util.h"
-#include "build.h"
#include "macro.h"
+#include "signal-util.h"
+#include "socket-util.h"
#include "strv.h"
-#include "fileio.h"
-#include "conf-parser.h"
-
-#ifdef HAVE_GNUTLS
-#include <gnutls/gnutls.h>
-#endif
-
-#include "journal-remote.h"
#include "journal-remote-write.h"
+#include "journal-remote.h"
#define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
@@ -648,9 +647,10 @@ static int setup_microhttpd_server(RemoteServer *s,
int opts_pos = 3;
int flags =
MHD_USE_DEBUG |
- MHD_USE_PEDANTIC_CHECKS |
+ MHD_USE_DUAL_STACK |
MHD_USE_EPOLL_LINUX_ONLY |
- MHD_USE_DUAL_STACK;
+ MHD_USE_PEDANTIC_CHECKS |
+ MHD_USE_PIPE_FOR_SHUTDOWN;
const union MHD_DaemonInfo *info;
int r, epoll_fd;
@@ -954,7 +954,7 @@ static int remoteserver_init(RemoteServer *s,
}
if (s->active == 0) {
- log_error("Zarro sources specified");
+ log_error("Zero sources specified");
return -EINVAL;
}
@@ -1259,9 +1259,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0 /* done */;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
case ARG_URL:
if (arg_url) {
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index 311bd3fdda..92ce56805a 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -19,22 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <curl/curl.h>
-#include <sys/stat.h>
#include <fcntl.h>
#include <getopt.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <curl/curl.h>
#include "sd-daemon.h"
-#include "log.h"
-#include "util.h"
-#include "build.h"
+
+#include "conf-parser.h"
#include "fileio.h"
+#include "formats-util.h"
+#include "log.h"
#include "mkdir.h"
-#include "conf-parser.h"
#include "sigbus.h"
-#include "formats-util.h"
#include "signal-util.h"
+#include "util.h"
#include "journal-upload.h"
#define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem"
@@ -619,9 +619,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0 /* done */;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
case 'u':
if (arg_url) {
diff --git a/src/journal/cat.c b/src/journal/cat.c
index be2c2e3354..f9b279d7de 100644
--- a/src/journal/cat.c
+++ b/src/journal/cat.c
@@ -19,17 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <getopt.h>
-#include <unistd.h>
-#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
-#include "systemd/sd-journal.h"
+#include "sd-journal.h"
#include "util.h"
-#include "build.h"
static char *arg_identifier = NULL;
static int arg_priority = LOG_INFO;
@@ -76,9 +75,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 't':
free(arg_identifier);
@@ -95,7 +92,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_priority = log_level_from_string(optarg);
if (arg_priority < 0) {
log_error("Failed to parse priority value.");
- return arg_priority;
+ return -EINVAL;
}
break;
@@ -103,10 +100,9 @@ static int parse_argv(int argc, char *argv[]) {
int k;
k = parse_boolean(optarg);
- if (k < 0) {
- log_error("Failed to parse level prefix value.");
- return k;
- }
+ if (k < 0)
+ return log_error_errno(k, "Failed to parse level prefix value.");
+
arg_level_prefix = k;
break;
}
@@ -122,7 +118,8 @@ static int parse_argv(int argc, char *argv[]) {
}
int main(int argc, char *argv[]) {
- int r, fd = -1, saved_stderr = -1;
+ _cleanup_close_ int fd = -1, saved_stderr = -1;
+ int r;
log_parse_environment();
log_open();
@@ -133,8 +130,7 @@ int main(int argc, char *argv[]) {
fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix);
if (fd < 0) {
- log_error_errno(fd, "Failed to create stream fd: %m");
- r = fd;
+ r = log_error_errno(fd, "Failed to create stream fd: %m");
goto finish;
}
@@ -148,25 +144,20 @@ int main(int argc, char *argv[]) {
if (fd >= 3)
safe_close(fd);
-
fd = -1;
if (argc <= optind)
- execl("/bin/cat", "/bin/cat", NULL);
+ (void) execl("/bin/cat", "/bin/cat", NULL);
else
- execvp(argv[optind], argv + optind);
-
+ (void) execvp(argv[optind], argv + optind);
r = -errno;
/* Let's try to restore a working stderr, so we can print the error message */
if (saved_stderr >= 0)
- dup3(saved_stderr, STDERR_FILENO, 0);
+ (void) dup3(saved_stderr, STDERR_FILENO, 0);
log_error_errno(r, "Failed to execute process: %m");
finish:
- safe_close(fd);
- safe_close(saved_stderr);
-
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/journal/catalog.c b/src/journal/catalog.c
index a3e51e2f52..4c43500ef5 100644
--- a/src/journal/catalog.c
+++ b/src/journal/catalog.c
@@ -62,21 +62,11 @@ typedef struct CatalogItem {
le64_t offset;
} CatalogItem;
-static unsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void catalog_hash_func(const void *p, struct siphash *state) {
const CatalogItem *i = p;
- uint64_t u;
- size_t l, sz;
- void *v;
- l = strlen(i->language);
- sz = sizeof(i->id) + l;
- v = alloca(sz);
-
- memcpy(mempcpy(v, &i->id, sizeof(i->id)), i->language, l);
-
- siphash24((uint8_t*) &u, v, sz, hash_key);
-
- return (unsigned long) u;
+ siphash24_compress(&i->id, sizeof(i->id), state);
+ siphash24_compress(i->language, strlen(i->language), state);
}
static int catalog_compare_func(const void *a, const void *b) {
@@ -419,8 +409,7 @@ int catalog_update(const char* database, const char* root, const char* const* di
log_debug("Reading file '%s'", *f);
r = catalog_import_file(h, sb, *f);
if (r < 0) {
- log_error("Failed to import file '%s': %s.",
- *f, strerror(-r));
+ log_error_errno(r, "Failed to import file '%s': %m", *f);
goto finish;
}
}
@@ -676,8 +665,7 @@ int catalog_list_items(FILE *f, const char *database, bool oneline, char **items
k = sd_id128_from_string(*item, &id);
if (k < 0) {
- log_error_errno(k, "Failed to parse id128 '%s': %m",
- *item);
+ log_error_errno(k, "Failed to parse id128 '%s': %m", *item);
if (r == 0)
r = k;
continue;
@@ -685,9 +673,8 @@ int catalog_list_items(FILE *f, const char *database, bool oneline, char **items
k = catalog_get(database, id, &msg);
if (k < 0) {
- log_full(k == -ENOENT ? LOG_NOTICE : LOG_ERR,
- "Failed to retrieve catalog entry for '%s': %s",
- *item, strerror(-k));
+ log_full_errno(k == -ENOENT ? LOG_NOTICE : LOG_ERR, k,
+ "Failed to retrieve catalog entry for '%s': %m", *item);
if (r == 0)
r = k;
continue;
diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c
index 0546290318..dde56008c1 100644
--- a/src/journal/coredumpctl.c
+++ b/src/journal/coredumpctl.c
@@ -19,27 +19,27 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fcntl.h>
+#include <getopt.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
-#include <getopt.h>
-#include <fcntl.h>
#include <unistd.h>
#include "sd-journal.h"
-#include "build.h"
-#include "set.h"
-#include "util.h"
+
+#include "compress.h"
+#include "journal-internal.h"
#include "log.h"
-#include "path-util.h"
-#include "pager.h"
#include "macro.h"
-#include "journal-internal.h"
-#include "compress.h"
-#include "sigbus.h"
+#include "pager.h"
+#include "path-util.h"
#include "process-util.h"
-#include "terminal-util.h"
+#include "set.h"
+#include "sigbus.h"
#include "signal-util.h"
+#include "terminal-util.h"
+#include "util.h"
static enum {
ACTION_NONE,
@@ -175,9 +175,7 @@ static int parse_argv(int argc, char *argv[], Set *matches) {
case ARG_VERSION:
arg_action = ACTION_NONE;
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
@@ -402,11 +400,11 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
if (comm)
fprintf(file,
" PID: %s%s%s (%s)\n",
- ansi_highlight(), strna(pid), ansi_highlight_off(), comm);
+ ansi_highlight(), strna(pid), ansi_normal(), comm);
else
fprintf(file,
" PID: %s%s%s\n",
- ansi_highlight(), strna(pid), ansi_highlight_off());
+ ansi_highlight(), strna(pid), ansi_normal());
if (uid) {
uid_t n;
@@ -470,7 +468,7 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) {
if (cmdline)
fprintf(file, " Command Line: %s\n", cmdline);
if (exe)
- fprintf(file, " Executable: %s%s%s\n", ansi_highlight(), exe, ansi_highlight_off());
+ fprintf(file, " Executable: %s%s%s\n", ansi_highlight(), exe, ansi_normal());
if (cgroup)
fprintf(file, " Control Group: %s\n", cgroup);
if (unit)
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 73d3a4bb9d..1071c6d6d7 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -49,6 +49,9 @@
#define DEFAULT_MAX_USE_LOWER (1ULL*1024ULL*1024ULL) /* 1 MiB */
#define DEFAULT_MAX_USE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */
+/* This is the default minimal use limit, how much we'll use even if keep_free suggests otherwise. */
+#define DEFAULT_MIN_USE (1ULL*1024ULL*1024ULL) /* 1 MiB */
+
/* This is the upper bound if we deduce max_size from max_use */
#define DEFAULT_MAX_SIZE_UPPER (128ULL*1024ULL*1024ULL) /* 128 MiB */
@@ -60,6 +63,9 @@
* size */
#define DEFAULT_KEEP_FREE (1024ULL*1024ULL) /* 1 MB */
+/* This is the default maximum number of journal files to keep around. */
+#define DEFAULT_N_MAX_FILES (100)
+
/* n_data was the first entry we added after the initial file format design */
#define HEADER_SIZE_MIN ALIGN64(offsetof(Header, n_data))
@@ -128,7 +134,7 @@ int journal_file_set_offline(JournalFile *f) {
return 0;
}
-void journal_file_close(JournalFile *f) {
+JournalFile* journal_file_close(JournalFile *f) {
assert(f);
#ifdef HAVE_GCRYPT
@@ -179,6 +185,7 @@ void journal_file_close(JournalFile *f) {
#endif
free(f);
+ return NULL;
}
static int journal_file_init_header(JournalFile *f, JournalFile *template) {
@@ -398,12 +405,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size)
if (fstatvfs(f->fd, &svfs) >= 0) {
uint64_t available;
- available = svfs.f_bfree * svfs.f_bsize;
-
- if (available >= f->metrics.keep_free)
- available -= f->metrics.keep_free;
- else
- available = 0;
+ available = LESS_BY((uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize, f->metrics.keep_free);
if (new_size - old_size > available)
return -E2BIG;
@@ -604,10 +606,10 @@ static int journal_file_setup_data_hash_table(JournalFile *f) {
assert(f);
- /* We estimate that we need 1 hash table entry per 768 of
- journal file and we want to make sure we never get beyond
- 75% fill level. Calculate the hash table size for the
- maximum file size based on these metrics. */
+ /* We estimate that we need 1 hash table entry per 768 bytes
+ of journal file and we want to make sure we never get
+ beyond 75% fill level. Calculate the hash table size for
+ the maximum file size based on these metrics. */
s = (f->metrics.max_size * 4 / 768 / 3) * sizeof(HashItem);
if (s < DEFAULT_DATA_HASH_TABLE_SIZE)
@@ -2833,8 +2835,7 @@ int journal_file_open_reliably(
size_t l;
_cleanup_free_ char *p = NULL;
- r = journal_file_open(fname, flags, mode, compress, seal,
- metrics, mmap_cache, template, ret);
+ r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret);
if (!IN_SET(r,
-EBADMSG, /* corrupted */
-ENODATA, /* truncated */
@@ -2864,8 +2865,7 @@ int journal_file_open_reliably(
random_u64()) < 0)
return -ENOMEM;
- r = rename(fname, p);
- if (r < 0)
+ if (rename(fname, p) < 0)
return -errno;
/* btrfs doesn't cope well with our write pattern and
@@ -2874,10 +2874,9 @@ int journal_file_open_reliably(
(void) chattr_path(p, false, FS_NOCOW_FL);
(void) btrfs_defrag(p);
- log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
+ log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
- return journal_file_open(fname, flags, mode, compress, seal,
- metrics, mmap_cache, template, ret);
+ return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret);
}
int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) {
@@ -2964,16 +2963,35 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
return r;
}
+void journal_reset_metrics(JournalMetrics *m) {
+ assert(m);
+
+ /* Set everything to "pick automatic values". */
+
+ *m = (JournalMetrics) {
+ .min_use = (uint64_t) -1,
+ .max_use = (uint64_t) -1,
+ .min_size = (uint64_t) -1,
+ .max_size = (uint64_t) -1,
+ .keep_free = (uint64_t) -1,
+ .n_max_files = (uint64_t) -1,
+ };
+}
+
void journal_default_metrics(JournalMetrics *m, int fd) {
- uint64_t fs_size = 0;
+ char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX], e[FORMAT_BYTES_MAX];
struct statvfs ss;
- char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX];
+ uint64_t fs_size;
assert(m);
assert(fd >= 0);
if (fstatvfs(fd, &ss) >= 0)
fs_size = ss.f_frsize * ss.f_blocks;
+ else {
+ log_debug_errno(errno, "Failed to detremine disk size: %m");
+ fs_size = 0;
+ }
if (m->max_use == (uint64_t) -1) {
@@ -2990,10 +3008,16 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
} else {
m->max_use = PAGE_ALIGN(m->max_use);
- if (m->max_use < JOURNAL_FILE_SIZE_MIN*2)
+ if (m->max_use != 0 && m->max_use < JOURNAL_FILE_SIZE_MIN*2)
m->max_use = JOURNAL_FILE_SIZE_MIN*2;
}
+ if (m->min_use == (uint64_t) -1)
+ m->min_use = DEFAULT_MIN_USE;
+
+ if (m->min_use > m->max_use)
+ m->min_use = m->max_use;
+
if (m->max_size == (uint64_t) -1) {
m->max_size = PAGE_ALIGN(m->max_use / 8); /* 8 chunks */
@@ -3002,11 +3026,13 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
} else
m->max_size = PAGE_ALIGN(m->max_size);
- if (m->max_size < JOURNAL_FILE_SIZE_MIN)
- m->max_size = JOURNAL_FILE_SIZE_MIN;
+ if (m->max_size != 0) {
+ if (m->max_size < JOURNAL_FILE_SIZE_MIN)
+ m->max_size = JOURNAL_FILE_SIZE_MIN;
- if (m->max_size*2 > m->max_use)
- m->max_use = m->max_size*2;
+ if (m->max_use != 0 && m->max_size*2 > m->max_use)
+ m->max_use = m->max_size*2;
+ }
if (m->min_size == (uint64_t) -1)
m->min_size = JOURNAL_FILE_SIZE_MIN;
@@ -3016,7 +3042,7 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
if (m->min_size < JOURNAL_FILE_SIZE_MIN)
m->min_size = JOURNAL_FILE_SIZE_MIN;
- if (m->min_size > m->max_size)
+ if (m->max_size != 0 && m->min_size > m->max_size)
m->max_size = m->min_size;
}
@@ -3032,11 +3058,16 @@ void journal_default_metrics(JournalMetrics *m, int fd) {
m->keep_free = DEFAULT_KEEP_FREE;
}
- log_debug("Fixed max_use=%s max_size=%s min_size=%s keep_free=%s",
- format_bytes(a, sizeof(a), m->max_use),
- format_bytes(b, sizeof(b), m->max_size),
- format_bytes(c, sizeof(c), m->min_size),
- format_bytes(d, sizeof(d), m->keep_free));
+ if (m->n_max_files == (uint64_t) -1)
+ m->n_max_files = DEFAULT_N_MAX_FILES;
+
+ log_debug("Fixed min_use=%s max_use=%s max_size=%s min_size=%s keep_free=%s n_max_files=%" PRIu64,
+ format_bytes(a, sizeof(a), m->min_use),
+ format_bytes(b, sizeof(b), m->max_use),
+ format_bytes(c, sizeof(c), m->max_size),
+ format_bytes(d, sizeof(d), m->min_size),
+ format_bytes(e, sizeof(e), m->keep_free),
+ m->n_max_files);
}
int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to) {
diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h
index e92b75eabe..f2c07356c8 100644
--- a/src/journal/journal-file.h
+++ b/src/journal/journal-file.h
@@ -36,11 +36,13 @@
#include "hashmap.h"
typedef struct JournalMetrics {
- uint64_t max_use;
- uint64_t use;
- uint64_t max_size;
- uint64_t min_size;
- uint64_t keep_free;
+ /* For all these: -1 means "pick automatically", and 0 means "no limit enforced" */
+ uint64_t max_size; /* how large journal files grow at max */
+ uint64_t min_size; /* how large journal files grow at least */
+ uint64_t max_use; /* how much disk space to use in total at max, keep_free permitting */
+ uint64_t min_use; /* how much disk space to use in total at least, even if keep_free says not to */
+ uint64_t keep_free; /* how much to keep free on disk */
+ uint64_t n_max_files; /* how many files to keep around at max */
} JournalMetrics;
typedef enum direction {
@@ -136,7 +138,7 @@ int journal_file_open(
JournalFile **ret);
int journal_file_set_offline(JournalFile *f);
-void journal_file_close(JournalFile *j);
+JournalFile* journal_file_close(JournalFile *j);
int journal_file_open_reliably(
const char *fname,
@@ -223,6 +225,7 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal);
void journal_file_post_change(JournalFile *f);
+void journal_reset_metrics(JournalMetrics *m);
void journal_default_metrics(JournalMetrics *m, int fd);
int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to);
diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index 1e3a463504..dc1b2105dd 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -212,11 +212,6 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
};
ssize_t k;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control;
- struct cmsghdr *cmsg;
bool have_syslog_identifier = false;
bool seal = true;
@@ -335,26 +330,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
return r;
}
- mh.msg_iov = NULL;
- mh.msg_iovlen = 0;
-
- zero(control);
- mh.msg_control = &control;
- mh.msg_controllen = sizeof(control);
-
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
- k = sendmsg(fd, &mh, MSG_NOSIGNAL);
- if (k < 0)
- return -errno;
-
- return 0;
+ return send_one_fd(fd, buffer_fd, 0);
}
static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) {
diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c
index 17499bbc30..a394066cb4 100644
--- a/src/journal/journal-vacuum.c
+++ b/src/journal/journal-vacuum.c
@@ -34,9 +34,9 @@ struct vacuum_info {
char *filename;
uint64_t realtime;
+
sd_id128_t seqnum_id;
uint64_t seqnum;
-
bool have_seqnum;
};
@@ -67,19 +67,18 @@ static int vacuum_compare(const void *_a, const void *_b) {
}
static void patch_realtime(
- const char *dir,
+ int fd,
const char *fn,
const struct stat *st,
unsigned long long *realtime) {
- _cleanup_free_ char *path = NULL;
usec_t x, crtime = 0;
/* The timestamp was determined by the file name, but let's
* see if the file might actually be older than the file name
* suggested... */
- assert(dir);
+ assert(fd >= 0);
assert(fn);
assert(st);
assert(realtime);
@@ -101,14 +100,7 @@ static void patch_realtime(
* unfortunately there's currently no sane API to query
* it. Hence let's implement this manually... */
- /* Unfortunately there is is not fgetxattrat(), so we need to
- * go via path here. :-( */
-
- path = strjoin(dir, "/", fn, NULL);
- if (!path)
- return;
-
- if (path_getcrtime(path, &crtime) >= 0) {
+ if (fd_getcrtime_at(fd, fn, &crtime, 0) >= 0) {
if (crtime < *realtime)
*realtime = crtime;
}
@@ -120,9 +112,13 @@ static int journal_file_empty(int dir_fd, const char *name) {
le64_t n_entries;
ssize_t n;
- fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
- if (fd < 0)
- return -errno;
+ fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK|O_NOATIME);
+ if (fd < 0) {
+ /* Maybe failed due to O_NOATIME and lack of privileges? */
+ fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK);
+ if (fd < 0)
+ return -errno;
+ }
if (fstat(fd, &st) < 0)
return -errno;
@@ -144,22 +140,24 @@ static int journal_file_empty(int dir_fd, const char *name) {
int journal_directory_vacuum(
const char *directory,
uint64_t max_use,
+ uint64_t n_max_files,
usec_t max_retention_usec,
usec_t *oldest_usec,
bool verbose) {
_cleanup_closedir_ DIR *d = NULL;
- int r = 0;
struct vacuum_info *list = NULL;
- unsigned n_list = 0, i;
+ unsigned n_list = 0, i, n_active_files = 0;
size_t n_allocated = 0;
uint64_t sum = 0, freed = 0;
usec_t retention_limit = 0;
char sbytes[FORMAT_BYTES_MAX];
+ struct dirent *de;
+ int r;
assert(directory);
- if (max_use <= 0 && max_retention_usec <= 0)
+ if (max_use <= 0 && max_retention_usec <= 0 && n_max_files <= 0)
return 0;
if (max_retention_usec > 0) {
@@ -174,27 +172,20 @@ int journal_directory_vacuum(
if (!d)
return -errno;
- for (;;) {
- struct dirent *de;
- size_t q;
- struct stat st;
- char *p;
+ FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) {
+
unsigned long long seqnum = 0, realtime;
+ _cleanup_free_ char *p = NULL;
sd_id128_t seqnum_id;
bool have_seqnum;
+ uint64_t size;
+ struct stat st;
+ size_t q;
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0) {
- r = -errno;
- goto finish;
- }
-
- if (!de)
- break;
-
- if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
+ if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+ log_debug_errno(errno, "Failed to stat file %s while vacuuming, ignoring: %m", de->d_name);
continue;
+ }
if (!S_ISREG(st.st_mode))
continue;
@@ -203,15 +194,20 @@ int journal_directory_vacuum(
if (endswith(de->d_name, ".journal")) {
- /* Vacuum archived files */
+ /* Vacuum archived files. Active files are
+ * left around */
- if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8)
+ if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) {
+ n_active_files++;
continue;
+ }
if (de->d_name[q-8-16-1] != '-' ||
de->d_name[q-8-16-1-16-1] != '-' ||
- de->d_name[q-8-16-1-16-1-32-1] != '@')
+ de->d_name[q-8-16-1-16-1-32-1] != '@') {
+ n_active_files++;
continue;
+ }
p = strdup(de->d_name);
if (!p) {
@@ -222,11 +218,13 @@ int journal_directory_vacuum(
de->d_name[q-8-16-1-16-1] = 0;
if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
free(p);
+ n_active_files++;
continue;
}
if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
free(p);
+ n_active_files++;
continue;
}
@@ -237,12 +235,16 @@ int journal_directory_vacuum(
/* Vacuum corrupted files */
- if (q < 1 + 16 + 1 + 16 + 8 + 1)
+ if (q < 1 + 16 + 1 + 16 + 8 + 1) {
+ n_active_files ++;
continue;
+ }
if (de->d_name[q-1-8-16-1] != '-' ||
- de->d_name[q-1-8-16-1-16-1] != '@')
+ de->d_name[q-1-8-16-1-16-1] != '@') {
+ n_active_files ++;
continue;
+ }
p = strdup(de->d_name);
if (!p) {
@@ -252,54 +254,68 @@ int journal_directory_vacuum(
if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
free(p);
+ n_active_files ++;
continue;
}
have_seqnum = false;
- } else
- /* We do not vacuum active files or unknown files! */
+ } else {
+ /* We do not vacuum unknown files! */
+ log_debug("Not vacuuming unknown file %s.", de->d_name);
continue;
+ }
- if (journal_file_empty(dirfd(d), p)) {
- /* Always vacuum empty non-online files. */
+ size = 512UL * (uint64_t) st.st_blocks;
- uint64_t size = 512UL * (uint64_t) st.st_blocks;
+ r = journal_file_empty(dirfd(d), p);
+ if (r < 0) {
+ log_debug_errno(r, "Failed check if %s is empty, ignoring: %m", p);
+ continue;
+ }
+ if (r > 0) {
+ /* Always vacuum empty non-online files. */
if (unlinkat(dirfd(d), p, 0) >= 0) {
- log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), size));
+
+ log_full(verbose ? LOG_INFO : LOG_DEBUG,
+ "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), size));
+
freed += size;
} else if (errno != ENOENT)
log_warning_errno(errno, "Failed to delete empty archived journal %s/%s: %m", directory, p);
- free(p);
continue;
}
- patch_realtime(directory, p, &st, &realtime);
+ patch_realtime(dirfd(d), p, &st, &realtime);
if (!GREEDY_REALLOC(list, n_allocated, n_list + 1)) {
- free(p);
r = -ENOMEM;
goto finish;
}
list[n_list].filename = p;
- list[n_list].usage = 512UL * (uint64_t) st.st_blocks;
+ list[n_list].usage = size;
list[n_list].seqnum = seqnum;
list[n_list].realtime = realtime;
list[n_list].seqnum_id = seqnum_id;
list[n_list].have_seqnum = have_seqnum;
-
- sum += list[n_list].usage;
-
n_list ++;
+
+ p = NULL;
+ sum += size;
}
qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare);
for (i = 0; i < n_list; i++) {
+ unsigned left;
+
+ left = n_active_files + n_list - i;
+
if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) &&
- (max_use <= 0 || sum <= max_use))
+ (max_use <= 0 || sum <= max_use) &&
+ (n_max_files <= 0 || left <= n_max_files))
break;
if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
@@ -318,6 +334,8 @@ int journal_directory_vacuum(
if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec))
*oldest_usec = list[i].realtime;
+ r = 0;
+
finish:
for (i = 0; i < n_list; i++)
free(list[i].filename);
diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h
index c45cc31d0e..49ab90af91 100644
--- a/src/journal/journal-vacuum.h
+++ b/src/journal/journal-vacuum.h
@@ -21,5 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <inttypes.h>
+#include <stdbool.h>
-int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec, bool vacuum);
+#include "time-util.h"
+
+int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t n_max_files, usec_t max_retention_usec, usec_t *oldest_usec, bool verbose);
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index 00f70d3a53..32d59c716f 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -53,12 +53,12 @@ static void draw_progress(uint64_t p, usec_t *last_usec) {
j = (n * (unsigned) p) / 65535ULL;
k = n - j;
- fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN_ON, stdout);
+ fputs("\r\x1B[?25l" ANSI_HIGHLIGHT_GREEN, stdout);
for (i = 0; i < j; i++)
fputs("\xe2\x96\x88", stdout);
- fputs(ANSI_HIGHLIGHT_OFF, stdout);
+ fputs(ANSI_NORMAL, stdout);
for (i = 0; i < k; i++)
fputs("\xe2\x96\x91", stdout);
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 9b483413e7..5dafb0bcab 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -19,48 +19,47 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <locale.h>
+#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
-#include <errno.h>
+#include <getopt.h>
+#include <linux/fs.h>
+#include <locale.h>
+#include <poll.h>
+#include <signal.h>
#include <stddef.h>
-#include <string.h>
#include <stdio.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <getopt.h>
-#include <signal.h>
-#include <poll.h>
-#include <sys/stat.h>
+#include <string.h>
#include <sys/inotify.h>
-#include <linux/fs.h>
+#include <sys/stat.h>
+#include <unistd.h>
-#include "sd-journal.h"
#include "sd-bus.h"
-#include "log.h"
-#include "logs-show.h"
-#include "util.h"
+#include "sd-journal.h"
+
#include "acl-util.h"
-#include "path-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "catalog.h"
#include "fileio.h"
-#include "build.h"
-#include "pager.h"
-#include "strv.h"
-#include "set.h"
-#include "sigbus.h"
-#include "journal-internal.h"
+#include "fsprg.h"
+#include "hostname-util.h"
#include "journal-def.h"
-#include "journal-verify.h"
+#include "journal-internal.h"
#include "journal-qrcode.h"
#include "journal-vacuum.h"
-#include "fsprg.h"
-#include "unit-name.h"
-#include "catalog.h"
+#include "journal-verify.h"
+#include "log.h"
+#include "logs-show.h"
#include "mkdir.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "pager.h"
+#include "path-util.h"
+#include "set.h"
+#include "sigbus.h"
+#include "strv.h"
#include "terminal-util.h"
-#include "hostname-util.h"
+#include "unit-name.h"
#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
@@ -107,8 +106,9 @@ static bool arg_reverse = false;
static int arg_journal_type = 0;
static const char *arg_root = NULL;
static const char *arg_machine = NULL;
-static uint64_t arg_vacuum_size = (uint64_t) -1;
-static usec_t arg_vacuum_time = USEC_INFINITY;
+static uint64_t arg_vacuum_size = 0;
+static uint64_t arg_vacuum_n_files = 0;
+static usec_t arg_vacuum_time = 0;
static enum {
ACTION_SHOW,
@@ -122,6 +122,7 @@ static enum {
ACTION_UPDATE_CATALOG,
ACTION_LIST_BOOTS,
ACTION_FLUSH,
+ ACTION_ROTATE,
ACTION_VACUUM,
} arg_action = ACTION_SHOW;
@@ -193,8 +194,8 @@ static void help(void) {
" --system Show the system journal\n"
" --user Show the user journal for the current user\n"
" -M --machine=CONTAINER Operate on local container\n"
- " --since=DATE Show entries not older than the specified date\n"
- " --until=DATE Show entries not newer than the specified date\n"
+ " -S --since=DATE Show entries not older than the specified date\n"
+ " -U --until=DATE Show entries not newer than the specified date\n"
" -c --cursor=CURSOR Show entries starting at the specified cursor\n"
" --after-cursor=CURSOR Show entries after the specified cursor\n"
" --show-cursor Print the cursor after all the entries\n"
@@ -235,8 +236,10 @@ static void help(void) {
" --new-id128 Generate a new 128-bit ID\n"
" --disk-usage Show total disk usage of all journal files\n"
" --vacuum-size=BYTES Reduce disk usage below specified size\n"
- " --vacuum-time=TIME Remove journal files older than specified date\n"
+ " --vacuum-files=INT Leave only the specified number of journal files\n"
+ " --vacuum-time=TIME Remove journal files older than specified time\n"
" --flush Flush all journal data from /run into /var\n"
+ " --rotate Request immediate rotation of the journal files\n"
" --header Show journal header information\n"
" --list-catalog Show all message IDs in the catalog\n"
" --dump-catalog Show entries in the message catalog\n"
@@ -267,8 +270,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERIFY,
ARG_VERIFY_KEY,
ARG_DISK_USAGE,
- ARG_SINCE,
- ARG_UNTIL,
ARG_AFTER_CURSOR,
ARG_SHOW_CURSOR,
ARG_USER_UNIT,
@@ -278,7 +279,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_FORCE,
ARG_UTC,
ARG_FLUSH,
+ ARG_ROTATE,
ARG_VACUUM_SIZE,
+ ARG_VACUUM_FILES,
ARG_VACUUM_TIME,
};
@@ -318,8 +321,8 @@ static int parse_argv(int argc, char *argv[]) {
{ "cursor", required_argument, NULL, 'c' },
{ "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
{ "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
- { "since", required_argument, NULL, ARG_SINCE },
- { "until", required_argument, NULL, ARG_UNTIL },
+ { "since", required_argument, NULL, 'S' },
+ { "until", required_argument, NULL, 'U' },
{ "unit", required_argument, NULL, 'u' },
{ "user-unit", required_argument, NULL, ARG_USER_UNIT },
{ "field", required_argument, NULL, 'F' },
@@ -331,7 +334,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "machine", required_argument, NULL, 'M' },
{ "utc", no_argument, NULL, ARG_UTC },
{ "flush", no_argument, NULL, ARG_FLUSH },
+ { "rotate", no_argument, NULL, ARG_ROTATE },
{ "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
+ { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
{ "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
{}
};
@@ -341,7 +346,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0)
switch (c) {
@@ -350,9 +355,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
@@ -539,6 +542,16 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_VACUUM;
break;
+ case ARG_VACUUM_FILES:
+ r = safe_atou64(optarg, &arg_vacuum_n_files);
+ if (r < 0) {
+ log_error("Failed to parse vacuum files: %s", optarg);
+ return r;
+ }
+
+ arg_action = ACTION_VACUUM;
+ break;
+
case ARG_VACUUM_TIME:
r = parse_sec(optarg, &arg_vacuum_time);
if (r < 0) {
@@ -631,7 +644,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
- case ARG_SINCE:
+ case 'S':
r = parse_timestamp(optarg, &arg_since);
if (r < 0) {
log_error("Failed to parse timestamp: %s", optarg);
@@ -640,7 +653,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_since_set = true;
break;
- case ARG_UNTIL:
+ case 'U':
r = parse_timestamp(optarg, &arg_until);
if (r < 0) {
log_error("Failed to parse timestamp: %s", optarg);
@@ -699,6 +712,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_FLUSH;
break;
+ case ARG_ROTATE:
+ arg_action = ACTION_ROTATE;
+ break;
+
case '?':
return -EINVAL;
@@ -729,7 +746,7 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- if (arg_action != ACTION_SHOW && optind < argc) {
+ if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) {
log_error("Extraneous arguments starting with '%s'", argv[optind]);
return -EINVAL;
}
@@ -1493,15 +1510,15 @@ static int setup_keys(void) {
if (on_tty()) {
fprintf(stderr,
"\n"
- "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
+ "The new key pair has been generated. The " ANSI_HIGHLIGHT "secret sealing key" ANSI_NORMAL " has been written to\n"
"the following local file. This key file is automatically updated when the\n"
"sealing key is advanced. It should not be used on multiple hosts.\n"
"\n"
"\t%s\n"
"\n"
- "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
+ "Please write down the following " ANSI_HIGHLIGHT "secret verification key" ANSI_NORMAL ". It should be stored\n"
"at a safe location and should not be saved locally on disk.\n"
- "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
+ "\n\t" ANSI_HIGHLIGHT_RED, p);
fflush(stderr);
}
for (i = 0; i < seed_size; i++) {
@@ -1516,7 +1533,7 @@ static int setup_keys(void) {
char tsb[FORMAT_TIMESPAN_MAX], *hn;
fprintf(stderr,
- ANSI_HIGHLIGHT_OFF "\n"
+ ANSI_NORMAL "\n"
"The sealing key is automatically changed every %s.\n",
format_timespan(tsb, sizeof(tsb), arg_interval, 0));
@@ -1580,7 +1597,7 @@ static int verify(sd_journal *j) {
/* If the key was invalid give up right-away. */
return k;
} else if (k < 0) {
- log_warning("FAIL: %s (%s)", f->path, strerror(-k));
+ log_warning_errno(k, "FAIL: %s (%m)", f->path);
r = k;
} else {
char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
@@ -1725,7 +1742,7 @@ static int flush_to_var(void) {
/* OK, let's actually do the full logic, send SIGUSR1 to the
* daemon and set up inotify to wait for the flushed file to appear */
- r = bus_open_system_systemd(&bus);
+ r = bus_connect_system_systemd(&bus);
if (r < 0)
return log_error_errno(r, "Failed to get D-Bus connection: %m");
@@ -1772,6 +1789,30 @@ static int flush_to_var(void) {
return 0;
}
+static int rotate(void) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ int r;
+
+ r = bus_connect_system_systemd(&bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get D-Bus connection: %m");
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "KillUnit",
+ &error,
+ NULL,
+ "ssi", "systemd-journald.service", "main", SIGUSR2);
+ if (r < 0)
+ return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
int r;
_cleanup_journal_close_ sd_journal *j = NULL;
@@ -1807,6 +1848,11 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (arg_action == ACTION_ROTATE) {
+ r = rotate();
+ goto finish;
+ }
+
if (arg_action == ACTION_SETUP_KEYS) {
r = setup_keys();
goto finish;
@@ -1831,6 +1877,7 @@ int main(int argc, char *argv[]) {
} else {
bool oneline = arg_action == ACTION_LIST_CATALOG;
+ pager_open_if_enabled();
if (optind < argc)
r = catalog_list_items(stdout, database,
oneline, argv + optind);
@@ -1895,9 +1942,9 @@ int main(int argc, char *argv[]) {
if (d->is_root)
continue;
- q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_time, NULL, true);
+ q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, true);
if (q < 0) {
- log_error_errno(q, "Failed to vacuum: %m");
+ log_error_errno(q, "Failed to vacuum %s: %m", d->path);
r = q;
}
}
@@ -2144,7 +2191,7 @@ int main(int argc, char *argv[]) {
if (previous_boot_id_valid &&
!sd_id128_equal(boot_id, previous_boot_id))
printf("%s-- Reboot --%s\n",
- ansi_highlight(), ansi_highlight_off());
+ ansi_highlight(), ansi_normal());
previous_boot_id = boot_id;
previous_boot_id_valid = true;
diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf
index bf7c773009..c154610c54 100644
--- a/src/journal/journald-gperf.gperf
+++ b/src/journal/journald-gperf.gperf
@@ -24,9 +24,11 @@ Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, rate_li
Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_use)
Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_size)
Journal.SystemKeepFree, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.keep_free)
+Journal.SystemMaxFiles, config_parse_uint64, 0, offsetof(Server, system_metrics.n_max_files)
Journal.RuntimeMaxUse, config_parse_iec_uint64, 0, offsetof(Server, runtime_metrics.max_use)
Journal.RuntimeMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, runtime_metrics.max_size)
Journal.RuntimeKeepFree, config_parse_iec_uint64, 0, offsetof(Server, runtime_metrics.keep_free)
+Journal.RuntimeMaxFiles, config_parse_uint64, 0, offsetof(Server, runtime_metrics.n_max_files)
Journal.MaxRetentionSec, config_parse_sec, 0, offsetof(Server, max_retention_usec)
Journal.MaxFileSec, config_parse_sec, 0, offsetof(Server, max_file_usec)
Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Server, forward_to_syslog)
diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c
index 6f83035a4e..8afd493b50 100644
--- a/src/journal/journald-rate-limit.c
+++ b/src/journal/journald-rate-limit.c
@@ -57,7 +57,7 @@ struct JournalRateLimitGroup {
char *id;
JournalRateLimitPool pools[POOLS_MAX];
- unsigned long hash;
+ uint64_t hash;
LIST_FIELDS(JournalRateLimitGroup, bucket);
LIST_FIELDS(JournalRateLimitGroup, lru);
@@ -145,6 +145,7 @@ static void journal_rate_limit_vacuum(JournalRateLimit *r, usec_t ts) {
static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, const char *id, usec_t ts) {
JournalRateLimitGroup *g;
+ struct siphash state;
assert(r);
assert(id);
@@ -157,7 +158,9 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r,
if (!g->id)
goto fail;
- g->hash = string_hash_func(g->id, r->hash_key);
+ siphash24_init(&state, r->hash_key);
+ string_hash_func(g->id, &state);
+ siphash24_finalize((uint8_t*)&g->hash, &state);
journal_rate_limit_vacuum(r, ts);
@@ -204,9 +207,10 @@ static unsigned burst_modulate(unsigned burst, uint64_t available) {
}
int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, uint64_t available) {
- unsigned long h;
+ uint64_t h;
JournalRateLimitGroup *g;
JournalRateLimitPool *p;
+ struct siphash state;
unsigned burst;
usec_t ts;
@@ -222,7 +226,9 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u
ts = now(CLOCK_MONOTONIC);
- h = string_hash_func(id, r->hash_key);
+ siphash24_init(&state, r->hash_key);
+ string_hash_func(id, &state);
+ siphash24_finalize((uint8_t*)&h, &state);
g = r->buckets[h % BUCKETS_MAX];
LIST_FOREACH(bucket, g, g)
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index fa2e9b9825..2d2a215f5d 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -19,45 +19,44 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/signalfd.h>
-#include <sys/ioctl.h>
#include <linux/sockios.h>
-#include <sys/statvfs.h>
-#include <sys/mman.h>
-
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/signalfd.h>
+#include <sys/statvfs.h>
-#include <libudev.h>
-
+#include "libudev.h"
+#include "sd-daemon.h"
#include "sd-journal.h"
#include "sd-messages.h"
-#include "sd-daemon.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "hashmap.h"
-#include "journal-file.h"
-#include "socket-util.h"
+
+#include "acl-util.h"
#include "cgroup-util.h"
-#include "missing.h"
#include "conf-parser.h"
-#include "selinux-util.h"
-#include "acl-util.h"
#include "formats-util.h"
-#include "process-util.h"
+#include "hashmap.h"
#include "hostname-util.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "process-util.h"
+#include "rm-rf.h"
+#include "selinux-util.h"
#include "signal-util.h"
+#include "socket-util.h"
+#include "journal-authenticate.h"
+#include "journal-file.h"
#include "journal-internal.h"
#include "journal-vacuum.h"
-#include "journal-authenticate.h"
-#include "journald-rate-limit.h"
+#include "journald-audit.h"
#include "journald-kmsg.h"
-#include "journald-syslog.h"
-#include "journald-stream.h"
#include "journald-native.h"
-#include "journald-audit.h"
+#include "journald-rate-limit.h"
#include "journald-server.h"
+#include "journald-stream.h"
+#include "journald-syslog.h"
#define USER_JOURNALS_MAX 1024
@@ -66,88 +65,61 @@
#define DEFAULT_RATE_LIMIT_BURST 1000
#define DEFAULT_MAX_FILE_USEC USEC_PER_MONTH
-#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC)
-
-static const char* const storage_table[_STORAGE_MAX] = {
- [STORAGE_AUTO] = "auto",
- [STORAGE_VOLATILE] = "volatile",
- [STORAGE_PERSISTENT] = "persistent",
- [STORAGE_NONE] = "none"
-};
+#define RECHECK_SPACE_USEC (30*USEC_PER_SEC)
-DEFINE_STRING_TABLE_LOOKUP(storage, Storage);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
-
-static const char* const split_mode_table[_SPLIT_MAX] = {
- [SPLIT_LOGIN] = "login",
- [SPLIT_UID] = "uid",
- [SPLIT_NONE] = "none",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
-
-static uint64_t available_space(Server *s, bool verbose) {
- char ids[33];
- _cleanup_free_ char *p = NULL;
- sd_id128_t machine;
- struct statvfs ss;
- uint64_t sum = 0, ss_avail = 0, avail = 0;
- int r;
+static int determine_space_for(
+ Server *s,
+ JournalMetrics *metrics,
+ const char *path,
+ const char *name,
+ bool verbose,
+ bool patch_min_use,
+ uint64_t *available,
+ uint64_t *limit) {
+
+ uint64_t sum = 0, ss_avail, avail;
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+ struct statvfs ss;
+ const char *p;
usec_t ts;
- const char *f;
- JournalMetrics *m;
+
+ assert(s);
+ assert(metrics);
+ assert(path);
+ assert(name);
ts = now(CLOCK_MONOTONIC);
- if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts
- && !verbose)
- return s->cached_available_space;
+ if (!verbose && s->cached_space_timestamp + RECHECK_SPACE_USEC > ts) {
- r = sd_id128_get_machine(&machine);
- if (r < 0)
- return 0;
+ if (available)
+ *available = s->cached_space_available;
+ if (limit)
+ *limit = s->cached_space_limit;
- if (s->system_journal) {
- f = "/var/log/journal/";
- m = &s->system_metrics;
- } else {
- f = "/run/log/journal/";
- m = &s->runtime_metrics;
- }
-
- assert(m);
-
- p = strappend(f, sd_id128_to_string(machine, ids));
- if (!p)
return 0;
+ }
+ p = strjoina(path, SERVER_MACHINE_ID(s));
d = opendir(p);
if (!d)
- return 0;
+ return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open %s: %m", p);
if (fstatvfs(dirfd(d), &ss) < 0)
- return 0;
+ return log_error_errno(errno, "Failed to fstatvfs(%s): %m", p);
- for (;;) {
+ FOREACH_DIRENT_ALL(de, d, break) {
struct stat st;
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno != 0)
- return 0;
-
- if (!de)
- break;
if (!endswith(de->d_name, ".journal") &&
!endswith(de->d_name, ".journal~"))
continue;
- if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
+ if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+ log_debug_errno(errno, "Failed to stat %s/%s, ignoring: %m", p, de->d_name);
continue;
+ }
if (!S_ISREG(st.st_mode))
continue;
@@ -155,45 +127,72 @@ static uint64_t available_space(Server *s, bool verbose) {
sum += (uint64_t) st.st_blocks * 512UL;
}
- ss_avail = ss.f_bsize * ss.f_bavail;
-
- /* If we reached a high mark, we will always allow this much
- * again, unless usage goes above max_use. This watermark
- * value is cached so that we don't give up space on pressure,
- * but hover below the maximum usage. */
+ /* If request, then let's bump the min_use limit to the
+ * current usage on disk. We do this when starting up and
+ * first opening the journal files. This way sudden spikes in
+ * disk usage will not cause journald to vacuum files without
+ * bounds. Note that this means that only a restart of
+ * journald will make it reset this value. */
- if (m->use < sum)
- m->use = sum;
+ if (patch_min_use)
+ metrics->min_use = MAX(metrics->min_use, sum);
- avail = LESS_BY(ss_avail, m->keep_free);
+ ss_avail = ss.f_bsize * ss.f_bavail;
+ avail = LESS_BY(ss_avail, metrics->keep_free);
- s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum);
- s->cached_available_space_timestamp = ts;
+ s->cached_space_limit = MIN(MAX(sum + avail, metrics->min_use), metrics->max_use);
+ s->cached_space_available = LESS_BY(s->cached_space_limit, sum);
+ s->cached_space_timestamp = ts;
if (verbose) {
char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX],
- fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX];
+ fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX], fb6[FORMAT_BYTES_MAX];
server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE,
- "%s is currently using %s.\n"
+ "%s (%s) is currently using %s.\n"
"Maximum allowed usage is set to %s.\n"
"Leaving at least %s free (of currently available %s of space).\n"
- "Enforced usage limit is thus %s.",
- s->system_journal ? "Permanent journal (/var/log/journal/)" : "Runtime journal (/run/log/journal/)",
+ "Enforced usage limit is thus %s, of which %s are still available.",
+ name, path,
format_bytes(fb1, sizeof(fb1), sum),
- format_bytes(fb2, sizeof(fb2), m->max_use),
- format_bytes(fb3, sizeof(fb3), m->keep_free),
+ format_bytes(fb2, sizeof(fb2), metrics->max_use),
+ format_bytes(fb3, sizeof(fb3), metrics->keep_free),
format_bytes(fb4, sizeof(fb4), ss_avail),
- format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum));
+ format_bytes(fb5, sizeof(fb5), s->cached_space_limit),
+ format_bytes(fb6, sizeof(fb6), s->cached_space_available));
}
- return s->cached_available_space;
+ if (available)
+ *available = s->cached_space_available;
+ if (limit)
+ *limit = s->cached_space_limit;
+
+ return 1;
+}
+
+static int determine_space(Server *s, bool verbose, bool patch_min_use, uint64_t *available, uint64_t *limit) {
+ JournalMetrics *metrics;
+ const char *path, *name;
+
+ assert(s);
+
+ if (s->system_journal) {
+ path = "/var/log/journal/";
+ metrics = &s->system_metrics;
+ name = "System journal";
+ } else {
+ path = "/run/log/journal/";
+ metrics = &s->runtime_metrics;
+ name = "Runtime journal";
+ }
+
+ return determine_space_for(s, metrics, path, name, verbose, patch_min_use, available, limit);
}
void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
int r;
#ifdef HAVE_ACL
- acl_t acl;
+ _cleanup_(acl_freep) acl_t acl = NULL;
acl_entry_t entry;
acl_permset_t permset;
#endif
@@ -202,7 +201,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
r = fchmod(f->fd, 0640);
if (r < 0)
- log_warning_errno(r, "Failed to fix access mode on %s, ignoring: %m", f->path);
+ log_warning_errno(errno, "Failed to fix access mode on %s, ignoring: %m", f->path);
#ifdef HAVE_ACL
if (uid <= SYSTEM_UID_MAX)
@@ -221,7 +220,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
acl_set_tag_type(entry, ACL_USER) < 0 ||
acl_set_qualifier(entry, &uid) < 0) {
log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
- goto finish;
+ return;
}
}
@@ -231,14 +230,12 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
acl_add_perm(permset, ACL_READ) < 0 ||
calc_acl_mask_if_needed(&acl) < 0) {
log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path);
- goto finish;
+ return;
}
if (acl_set_fd(f->fd, acl) < 0)
log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path);
-finish:
- acl_free(acl);
#endif
}
@@ -328,8 +325,8 @@ void server_rotate(Server *s) {
log_debug("Rotating...");
- do_rotate(s, &s->runtime_journal, "runtime", false, 0);
- do_rotate(s, &s->system_journal, "system", s->seal, 0);
+ (void) do_rotate(s, &s->runtime_journal, "runtime", false, 0);
+ (void) do_rotate(s, &s->system_journal, "system", s->seal, 0);
ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
r = do_rotate(s, &f, "user", s->seal, PTR_TO_UINT32(k));
@@ -350,13 +347,13 @@ void server_sync(Server *s) {
if (s->system_journal) {
r = journal_file_set_offline(s->system_journal);
if (r < 0)
- log_error_errno(r, "Failed to sync system journal: %m");
+ log_warning_errno(r, "Failed to sync system journal, ignoring: %m");
}
ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) {
r = journal_file_set_offline(f);
if (r < 0)
- log_error_errno(r, "Failed to sync user journal: %m");
+ log_warning_errno(r, "Failed to sync user journal, ignoring: %m");
}
if (s->sync_event_source) {
@@ -370,43 +367,50 @@ void server_sync(Server *s) {
static void do_vacuum(
Server *s,
- const char *id,
JournalFile *f,
- const char* path,
- JournalMetrics *metrics) {
+ JournalMetrics *metrics,
+ const char *path,
+ const char *name,
+ bool verbose,
+ bool patch_min_use) {
const char *p;
+ uint64_t limit;
int r;
+ assert(s);
+ assert(metrics);
+ assert(path);
+ assert(name);
+
if (!f)
return;
- p = strjoina(path, id);
- r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec, false);
+ p = strjoina(path, SERVER_MACHINE_ID(s));
+
+ limit = metrics->max_use;
+ (void) determine_space_for(s, metrics, path, name, verbose, patch_min_use, NULL, &limit);
+
+ r = journal_directory_vacuum(p, limit, metrics->n_max_files, s->max_retention_usec, &s->oldest_file_usec, verbose);
if (r < 0 && r != -ENOENT)
- log_error_errno(r, "Failed to vacuum %s: %m", p);
+ log_warning_errno(r, "Failed to vacuum %s, ignoring: %m", p);
}
-void server_vacuum(Server *s) {
- char ids[33];
- sd_id128_t machine;
- int r;
+int server_vacuum(Server *s, bool verbose, bool patch_min_use) {
+ assert(s);
log_debug("Vacuuming...");
s->oldest_file_usec = 0;
- r = sd_id128_get_machine(&machine);
- if (r < 0) {
- log_error_errno(r, "Failed to get machine ID: %m");
- return;
- }
- sd_id128_to_string(machine, ids);
+ do_vacuum(s, s->system_journal, &s->system_metrics, "/var/log/journal/", "System journal", verbose, patch_min_use);
+ do_vacuum(s, s->runtime_journal, &s->runtime_metrics, "/run/log/journal/", "Runtime journal", verbose, patch_min_use);
- do_vacuum(s, ids, s->system_journal, "/var/log/journal/", &s->system_metrics);
- do_vacuum(s, ids, s->runtime_journal, "/run/log/journal/", &s->runtime_metrics);
+ s->cached_space_limit = 0;
+ s->cached_space_available = 0;
+ s->cached_space_timestamp = 0;
- s->cached_available_space_timestamp = 0;
+ return 0;
}
static void server_cache_machine_id(Server *s) {
@@ -504,7 +508,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
if (journal_file_rotate_suggested(f, s->max_file_usec)) {
log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path);
server_rotate(s);
- server_vacuum(s);
+ server_vacuum(s, false, false);
vacuumed = true;
f = find_journal(s, uid);
@@ -524,7 +528,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned
}
server_rotate(s);
- server_vacuum(s);
+ server_vacuum(s, false, false);
f = find_journal(s, uid);
if (!f)
@@ -825,7 +829,7 @@ static void dispatch_message_real(
void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) {
char mid[11 + 32 + 1];
char buffer[16 + LINE_MAX + 1];
- struct iovec iovec[N_IOVEC_META_FIELDS + 4];
+ struct iovec iovec[N_IOVEC_META_FIELDS + 6];
int n = 0;
va_list ap;
struct ucred ucred = {};
@@ -833,6 +837,9 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format,
assert(s);
assert(format);
+ IOVEC_SET_STRING(iovec[n++], "SYSLOG_FACILITY=3");
+ IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=systemd-journald");
+
IOVEC_SET_STRING(iovec[n++], "PRIORITY=6");
IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver");
@@ -866,6 +873,7 @@ void server_dispatch_message(
int rl, r;
_cleanup_free_ char *path = NULL;
+ uint64_t available = 0;
char *c;
assert(s);
@@ -905,9 +913,8 @@ void server_dispatch_message(
}
}
- rl = journal_rate_limit_test(s->rate_limit, path,
- priority & LOG_PRIMASK, available_space(s, false));
-
+ (void) determine_space(s, false, false, &available, NULL);
+ rl = journal_rate_limit_test(s->rate_limit, path, priority & LOG_PRIMASK, available);
if (rl == 0)
return;
@@ -922,16 +929,8 @@ finish:
static int system_journal_open(Server *s, bool flush_requested) {
+ const char *fn;
int r;
- char *fn;
- sd_id128_t machine;
- char ids[33];
-
- r = sd_id128_get_machine(&machine);
- if (r < 0)
- return log_error_errno(r, "Failed to get machine id: %m");
-
- sd_id128_to_string(machine, ids);
if (!s->system_journal &&
(s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) &&
@@ -947,15 +946,15 @@ static int system_journal_open(Server *s, bool flush_requested) {
if (s->storage == STORAGE_PERSISTENT)
(void) mkdir_p("/var/log/journal/", 0755);
- fn = strjoina("/var/log/journal/", ids);
+ fn = strjoina("/var/log/journal/", SERVER_MACHINE_ID(s));
(void) mkdir(fn, 0755);
fn = strjoina(fn, "/system.journal");
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);
-
- if (r >= 0)
+ if (r >= 0) {
server_fix_perms(s, s->system_journal, 0);
- else if (r < 0) {
+ (void) determine_space_for(s, &s->system_metrics, "/var/log/journal/", "System journal", true, true, NULL, NULL);
+ } else if (r < 0) {
if (r != -ENOENT && r != -EROFS)
log_warning_errno(r, "Failed to open system journal: %m");
@@ -966,9 +965,7 @@ static int system_journal_open(Server *s, bool flush_requested) {
if (!s->runtime_journal &&
(s->storage != STORAGE_NONE)) {
- fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL);
- if (!fn)
- return -ENOMEM;
+ fn = strjoina("/run/log/journal/", SERVER_MACHINE_ID(s), "/system.journal");
if (s->system_journal) {
@@ -977,8 +974,6 @@ static int system_journal_open(Server *s, bool flush_requested) {
* it into the system journal */
r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
- free(fn);
-
if (r < 0) {
if (r != -ENOENT)
log_warning_errno(r, "Failed to open runtime journal: %m");
@@ -996,18 +991,16 @@ static int system_journal_open(Server *s, bool flush_requested) {
(void) mkdir_parents(fn, 0750);
r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal);
- free(fn);
-
if (r < 0)
return log_error_errno(r, "Failed to open runtime journal: %m");
}
- if (s->runtime_journal)
+ if (s->runtime_journal) {
server_fix_perms(s, s->runtime_journal, 0);
+ (void) determine_space_for(s, &s->runtime_metrics, "/run/log/journal/", "Runtime journal", true, true, NULL, NULL);
+ }
}
- available_space(s, true);
-
return r;
}
@@ -1028,7 +1021,7 @@ int server_flush_to_var(Server *s) {
if (!s->runtime_journal)
return 0;
- system_journal_open(s, true);
+ (void) system_journal_open(s, true);
if (!s->system_journal)
return 0;
@@ -1072,7 +1065,7 @@ int server_flush_to_var(Server *s) {
}
server_rotate(s);
- server_vacuum(s);
+ server_vacuum(s, false, false);
if (!s->system_journal) {
log_notice("Didn't flush runtime journal since rotation of system journal wasn't successful.");
@@ -1088,11 +1081,12 @@ int server_flush_to_var(Server *s) {
}
}
+ r = 0;
+
finish:
journal_file_post_change(s->system_journal);
- journal_file_close(s->runtime_journal);
- s->runtime_journal = NULL;
+ s->runtime_journal = journal_file_close(s->runtime_journal);
if (r >= 0)
(void) rm_rf("/run/log/journal", REMOVE_ROOT);
@@ -1235,7 +1229,7 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *
server_flush_to_var(s);
server_sync(s);
- server_vacuum(s);
+ server_vacuum(s, false, false);
touch("/run/systemd/journal/flushed");
@@ -1249,7 +1243,7 @@ static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *
log_info("Received request to rotate journal from PID %"PRIu32, si->ssi_pid);
server_rotate(s);
- server_vacuum(s);
+ server_vacuum(s, true, true);
return 0;
}
@@ -1337,8 +1331,8 @@ static int server_parse_proc_cmdline(Server *s) {
} else if (startswith(word, "systemd.journald"))
log_warning("Invalid systemd.journald parameter. Ignoring.");
}
- /* do not warn about state here, since probably systemd already did */
+ /* do not warn about state here, since probably systemd already did */
return 0;
}
@@ -1434,8 +1428,7 @@ static int server_open_hostname(Server *s) {
/* kernels prior to 3.2 don't support polling this file. Ignore
* the failure. */
if (r == -EPERM) {
- log_warning("Failed to register hostname fd in event loop: %s. Ignoring.",
- strerror(-r));
+ log_warning_errno(r, "Failed to register hostname fd in event loop, ignoring: %m");
s->hostname_fd = safe_close(s->hostname_fd);
return 0;
}
@@ -1453,6 +1446,7 @@ static int server_open_hostname(Server *s) {
int server_init(Server *s) {
_cleanup_fdset_free_ FDSet *fds = NULL;
int n, r, fd;
+ bool no_sockets;
assert(s);
@@ -1477,18 +1471,19 @@ int server_init(Server *s) {
s->max_level_console = LOG_INFO;
s->max_level_wall = LOG_EMERG;
- memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics));
- memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics));
+ journal_reset_metrics(&s->system_metrics);
+ journal_reset_metrics(&s->runtime_metrics);
server_parse_config_file(s);
server_parse_proc_cmdline(s);
+
if (!!s->rate_limit_interval ^ !!s->rate_limit_burst) {
log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0",
s->rate_limit_interval, s->rate_limit_burst);
s->rate_limit_interval = s->rate_limit_burst = 0;
}
- mkdir_p("/run/systemd/journal", 0755);
+ (void) mkdir_p("/run/systemd/journal", 0755);
s->user_journals = ordered_hashmap_new(NULL);
if (!s->user_journals)
@@ -1561,30 +1556,44 @@ int server_init(Server *s) {
}
}
- r = server_open_stdout_socket(s, fds);
- if (r < 0)
- return r;
+ /* Try to restore streams, but don't bother if this fails */
+ (void) server_restore_streams(s, fds);
if (fdset_size(fds) > 0) {
log_warning("%u unknown file descriptors passed, closing.", fdset_size(fds));
fds = fdset_free(fds);
}
+ no_sockets = s->native_fd < 0 && s->stdout_fd < 0 && s->syslog_fd < 0 && s->audit_fd < 0;
+
+ /* always open stdout, syslog, native, and kmsg sockets */
+
+ /* systemd-journald.socket: /run/systemd/journal/stdout */
+ r = server_open_stdout_socket(s);
+ if (r < 0)
+ return r;
+
+ /* systemd-journald-dev-log.socket: /run/systemd/journal/dev-log */
r = server_open_syslog_socket(s);
if (r < 0)
return r;
+ /* systemd-journald.socket: /run/systemd/journal/socket */
r = server_open_native_socket(s);
if (r < 0)
return r;
+ /* /dev/ksmg */
r = server_open_dev_kmsg(s);
if (r < 0)
return r;
- r = server_open_audit(s);
- if (r < 0)
- return r;
+ /* Unless we got *some* sockets and not audit, open audit socket */
+ if (s->audit_fd >= 0 || no_sockets) {
+ r = server_open_audit(s);
+ if (r < 0)
+ return r;
+ }
r = server_open_kernel_seqnum(s);
if (r < 0)
@@ -1614,11 +1623,7 @@ int server_init(Server *s) {
server_cache_boot_id(s);
server_cache_machine_id(s);
- r = system_journal_open(s, false);
- if (r < 0)
- return r;
-
- return 0;
+ return system_journal_open(s, false);
}
void server_maybe_append_tags(Server *s) {
@@ -1691,3 +1696,22 @@ void server_done(Server *s) {
udev_unref(s->udev);
}
+
+static const char* const storage_table[_STORAGE_MAX] = {
+ [STORAGE_AUTO] = "auto",
+ [STORAGE_VOLATILE] = "volatile",
+ [STORAGE_PERSISTENT] = "persistent",
+ [STORAGE_NONE] = "none"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(storage, Storage);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting");
+
+static const char* const split_mode_table[_SPLIT_MAX] = {
+ [SPLIT_LOGIN] = "login",
+ [SPLIT_UID] = "uid",
+ [SPLIT_NONE] = "none",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting");
diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h
index d954c5190d..535c0ab9ab 100644
--- a/src/journal/journald-server.h
+++ b/src/journal/journald-server.h
@@ -100,8 +100,9 @@ typedef struct Server {
unsigned n_forward_syslog_missed;
usec_t last_warn_forward_syslog_missed;
- uint64_t cached_available_space;
- usec_t cached_available_space_timestamp;
+ uint64_t cached_space_available;
+ uint64_t cached_space_limit;
+ usec_t cached_space_timestamp;
uint64_t var_available_timestamp;
@@ -141,6 +142,8 @@ typedef struct Server {
char *cgroup_root;
} Server;
+#define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID="))
+
#define N_IOVEC_META_FIELDS 20
#define N_IOVEC_KERNEL_FIELDS 64
#define N_IOVEC_UDEV_FIELDS 32
@@ -166,7 +169,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid);
int server_init(Server *s);
void server_done(Server *s);
void server_sync(Server *s);
-void server_vacuum(Server *s);
+int server_vacuum(Server *s, bool verbose, bool patch_min_use);
void server_rotate(Server *s);
int server_schedule_sync(Server *s, int priority);
int server_flush_to_var(Server *s);
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 69e2d41863..cbdaa3b888 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -627,7 +627,7 @@ static int stdout_stream_restore(Server *s, const char *fname, int fd) {
return 0;
}
-static int server_restore_streams(Server *s, FDSet *fds) {
+int server_restore_streams(Server *s, FDSet *fds) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r;
@@ -681,7 +681,7 @@ fail:
return log_error_errno(errno, "Failed to read streams directory: %m");
}
-int server_open_stdout_socket(Server *s, FDSet *fds) {
+int server_open_stdout_socket(Server *s) {
int r;
assert(s);
@@ -717,8 +717,5 @@ int server_open_stdout_socket(Server *s, FDSet *fds) {
if (r < 0)
return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m");
- /* Try to restore streams, but don't bother if this fails */
- (void) server_restore_streams(s, fds);
-
return 0;
}
diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h
index 94bf955d78..257dce45df 100644
--- a/src/journal/journald-stream.h
+++ b/src/journal/journald-stream.h
@@ -24,6 +24,6 @@
#include "fdset.h"
#include "journald-server.h"
-int server_open_stdout_socket(Server *s, FDSet *fds);
-
+int server_open_stdout_socket(Server *s);
+int server_restore_streams(Server *s, FDSet *fds);
void stdout_stream_free(StdoutStream *s);
diff --git a/src/journal/journald.c b/src/journal/journald.c
index b2624c6d28..83236ceba9 100644
--- a/src/journal/journald.c
+++ b/src/journal/journald.c
@@ -21,8 +21,8 @@
#include <unistd.h>
-#include "systemd/sd-messages.h"
-#include "systemd/sd-daemon.h"
+#include "sd-messages.h"
+#include "sd-daemon.h"
#include "journal-authenticate.h"
#include "journald-server.h"
@@ -54,7 +54,7 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
- server_vacuum(&server);
+ server_vacuum(&server, false, false);
server_flush_to_var(&server);
server_flush_dev_kmsg(&server);
@@ -82,7 +82,7 @@ int main(int argc, char *argv[]) {
if (server.oldest_file_usec + server.max_retention_usec < n) {
log_info("Retention time reached.");
server_rotate(&server);
- server_vacuum(&server);
+ server_vacuum(&server, false, false);
continue;
}
diff --git a/src/journal/journald.conf b/src/journal/journald.conf
index 47eefe91c1..7beb96c671 100644
--- a/src/journal/journald.conf
+++ b/src/journal/journald.conf
@@ -22,9 +22,11 @@
#SystemMaxUse=
#SystemKeepFree=
#SystemMaxFileSize=
+#SystemMaxFiles=100
#RuntimeMaxUse=
#RuntimeKeepFree=
#RuntimeMaxFileSize=
+#RuntimeMaxFiles=100
#MaxRetentionSec=
#MaxFileSec=1month
#ForwardToSyslog=no
diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c
index adefa1b026..8069339c1f 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/journal/test-journal-interleaving.c
@@ -197,7 +197,7 @@ static void test_skip(void (*setup)(void)) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL, true);
+ journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
@@ -282,7 +282,7 @@ static void test_sequence_numbers(void) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL, true);
+ journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c
index 9dd9cb853f..d89123dc64 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/journal/test-journal-verify.c
@@ -137,7 +137,7 @@ int main(int argc, char *argv[]) {
log_info("[ %"PRIu64"+%"PRIu64"]", p / 8, p % 8);
if (raw_verify("test.journal", verification_key) >= 0)
- log_notice(ANSI_HIGHLIGHT_RED_ON ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_HIGHLIGHT_OFF, p / 8, p % 8);
+ log_notice(ANSI_HIGHLIGHT_RED ">>>> %"PRIu64" (bit %"PRIu64") can be toggled without detection." ANSI_NORMAL, p / 8, p % 8);
bit_toggle("test.journal", p);
}
diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c
index caaab258c9..01d4bc968a 100644
--- a/src/journal/test-journal.c
+++ b/src/journal/test-journal.c
@@ -116,7 +116,7 @@ static void test_non_empty(void) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL, true);
+ journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
@@ -155,7 +155,7 @@ static void test_empty(void) {
if (arg_keep)
log_info("Not removing %s", t);
else {
- journal_directory_vacuum(".", 3000000, 0, NULL, true);
+ journal_directory_vacuum(".", 3000000, 0, 0, NULL, true);
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
diff --git a/src/libsystemd-network/arp-util.c b/src/libsystemd-network/arp-util.c
new file mode 100644
index 0000000000..2f5b9b3731
--- /dev/null
+++ b/src/libsystemd-network/arp-util.c
@@ -0,0 +1,153 @@
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Axis Communications AB. All rights reserved.
+ Copyright (C) 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <linux/filter.h>
+#include <arpa/inet.h>
+
+#include "util.h"
+#include "arp-util.h"
+
+int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) {
+ struct sock_filter filter[] = {
+ BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
+ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hln)), /* A <- hardware address length */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct ether_addr), 1, 0), /* length == sizeof(ether_addr)? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pln)), /* A <- protocol address length */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct in_addr), 1, 0), /* length == sizeof(in_addr) ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* protocol == request ? */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ /* Sender Hardware Address must be different from our own */
+ BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((uint32_t *) eth_mac))), /* A <- 4 bytes of client's MAC */
+ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */
+ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 6), /* A == 0 ? */
+ BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((uint16_t *) (((char *) eth_mac) + 4)))), /* A <- remainder of client's MAC */
+ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */
+ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ /* Sender Protocol Address or Target Protocol Address must be equal to the one we care about*/
+ BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */
+ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */
+ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
+ BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
+ BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */
+ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */
+ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
+ BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ };
+ struct sock_fprog fprog = {
+ .len = ELEMENTSOF(filter),
+ .filter = (struct sock_filter*) filter
+ };
+ union sockaddr_union link = {
+ .ll.sll_family = AF_PACKET,
+ .ll.sll_protocol = htons(ETH_P_ARP),
+ .ll.sll_ifindex = ifindex,
+ .ll.sll_halen = ETH_ALEN,
+ .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ };
+ _cleanup_close_ int s = -1;
+ int r;
+
+ assert(ifindex > 0);
+
+ s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+ if (s < 0)
+ return -errno;
+
+ r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
+ if (r < 0)
+ return -errno;
+
+ r = bind(s, &link.sa, sizeof(link.ll));
+ if (r < 0)
+ return -errno;
+
+ r = s;
+ s = -1;
+
+ return r;
+}
+
+static int arp_send_packet(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha,
+ bool announce) {
+ union sockaddr_union link = {
+ .ll.sll_family = AF_PACKET,
+ .ll.sll_protocol = htons(ETH_P_ARP),
+ .ll.sll_ifindex = ifindex,
+ .ll.sll_halen = ETH_ALEN,
+ .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ };
+ struct ether_arp arp = {
+ .ea_hdr.ar_hrd = htons(ARPHRD_ETHER), /* HTYPE */
+ .ea_hdr.ar_pro = htons(ETHERTYPE_IP), /* PTYPE */
+ .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */
+ .ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */
+ .ea_hdr.ar_op = htons(ARPOP_REQUEST), /* REQUEST */
+ };
+ int r;
+
+ assert(fd >= 0);
+ assert(pa != 0);
+ assert(ha);
+
+ memcpy(&arp.arp_sha, ha, ETH_ALEN);
+ memcpy(&arp.arp_tpa, &pa, sizeof(pa));
+
+ if (announce)
+ memcpy(&arp.arp_spa, &pa, sizeof(pa));
+
+ r = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll));
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+int arp_send_probe(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha) {
+ return arp_send_packet(fd, ifindex, pa, ha, false);
+}
+
+int arp_send_announcement(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha) {
+ return arp_send_packet(fd, ifindex, pa, ha, true);
+}
diff --git a/src/libsystemd-network/ipv4ll-internal.h b/src/libsystemd-network/arp-util.h
index ae0ce43985..44e5c893a7 100644
--- a/src/libsystemd-network/ipv4ll-internal.h
+++ b/src/libsystemd-network/arp-util.h
@@ -26,13 +26,9 @@
#include "sparse-endian.h"
#include "socket-util.h"
-int arp_network_bind_raw_socket(int index, union sockaddr_union *link);
-int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
- const struct ether_arp *arp);
+int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac);
-void arp_packet_init(struct ether_arp *arp);
-void arp_packet_probe(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha);
-void arp_packet_announcement(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha);
-int arp_packet_verify_headers(struct ether_arp *arp);
-
-#define log_ipv4ll(ll, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "IPv4LL: " fmt, ##__VA_ARGS__)
+int arp_send_probe(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha);
+int arp_send_announcement(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha);
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h
index 5dc3c7aa26..3b88b93d9a 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -96,5 +96,5 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
DHCPRequest *req, DHCPPacket *packet,
int type, size_t optoffset);
-unsigned long client_id_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]);
+void client_id_hash_func(const void *p, struct siphash *state);
int client_id_compare_func(const void *_a, const void *_b);
diff --git a/src/libsystemd-network/ipv4ll-network.c b/src/libsystemd-network/ipv4ll-network.c
deleted file mode 100644
index 93ffed408f..0000000000
--- a/src/libsystemd-network/ipv4ll-network.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Axis Communications AB. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <linux/filter.h>
-
-#include "util.h"
-#include "ipv4ll-internal.h"
-
-int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
- const struct ether_arp *arp) {
- int r;
-
- assert(arp);
- assert(link);
- assert(fd >= 0);
-
- r = sendto(fd, arp, sizeof(struct ether_arp), 0, &link->sa, sizeof(link->ll));
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-int arp_network_bind_raw_socket(int ifindex, union sockaddr_union *link) {
-
- static const struct sock_filter filter[] = {
- BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
- BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 0, 1), /* protocol == request ? */
- BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1), /* protocol == reply ? */
- BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- };
- struct sock_fprog fprog = {
- .len = ELEMENTSOF(filter),
- .filter = (struct sock_filter*) filter
- };
- _cleanup_close_ int s = -1;
- int r;
-
- assert(ifindex > 0);
- assert(link);
-
- s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (s < 0)
- return -errno;
-
- r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
- if (r < 0)
- return -errno;
-
- link->ll.sll_family = AF_PACKET;
- link->ll.sll_protocol = htons(ETH_P_ARP);
- link->ll.sll_ifindex = ifindex;
- link->ll.sll_halen = ETH_ALEN;
- memset(link->ll.sll_addr, 0xff, ETH_ALEN);
-
- r = bind(s, &link->sa, sizeof(link->ll));
- if (r < 0)
- return -errno;
-
- r = s;
- s = -1;
-
- return r;
-}
diff --git a/src/libsystemd-network/ipv4ll-packet.c b/src/libsystemd-network/ipv4ll-packet.c
deleted file mode 100644
index 2b6c73ab4b..0000000000
--- a/src/libsystemd-network/ipv4ll-packet.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Axis Communications AB. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-#include <arpa/inet.h>
-
-#include "util.h"
-#include "ipv4ll-internal.h"
-
-void arp_packet_init(struct ether_arp *arp) {
- assert(arp);
-
- memzero(arp, sizeof(struct ether_arp));
- /* Header */
- arp->ea_hdr.ar_hrd = htons(ARPHRD_ETHER); /* HTYPE */
- arp->ea_hdr.ar_pro = htons(ETHERTYPE_IP); /* PTYPE */
- arp->ea_hdr.ar_hln = ETH_ALEN; /* HLEN */
- arp->ea_hdr.ar_pln = sizeof arp->arp_spa; /* PLEN */
- arp->ea_hdr.ar_op = htons(ARPOP_REQUEST); /* REQUEST */
-}
-
-void arp_packet_probe(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha) {
- assert(ha);
-
- arp_packet_init(arp);
- memcpy(arp->arp_sha, ha, ETH_ALEN);
- memcpy(arp->arp_tpa, &pa, sizeof(pa));
-}
-
-void arp_packet_announcement(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha) {
- assert(ha);
-
- arp_packet_init(arp);
- memcpy(arp->arp_sha, ha, ETH_ALEN);
- memcpy(arp->arp_tpa, &pa, sizeof(pa));
- memcpy(arp->arp_spa, &pa, sizeof(pa));
-}
-
-int arp_packet_verify_headers(struct ether_arp *arp) {
- assert(arp);
-
- if (arp->ea_hdr.ar_hrd != htons(ARPHRD_ETHER)) {
- log_ipv4ll(NULL, "ignoring packet: header is not ARPHRD_ETHER");
- return -EINVAL;
- }
- if (arp->ea_hdr.ar_pro != htons(ETHERTYPE_IP)) {
- log_ipv4ll(NULL, "ignoring packet: protocol is not ETHERTYPE_IP");
- return -EINVAL;
- }
- if (arp->ea_hdr.ar_op != htons(ARPOP_REQUEST) &&
- arp->ea_hdr.ar_op != htons(ARPOP_REPLY)) {
- log_ipv4ll(NULL, "ignoring packet: operation is not ARPOP_REQUEST or ARPOP_REPLY");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c
index 3c04898e92..4012cd483b 100644
--- a/src/libsystemd-network/lldp-internal.c
+++ b/src/libsystemd-network/lldp-internal.c
@@ -21,6 +21,7 @@
***/
#include "lldp-internal.h"
+#include "sd-lldp.h"
/* We store maximum 1K chassis entries */
#define LLDP_MIB_MAX_CHASSIS 1024
@@ -28,207 +29,6 @@
/* Maximum Ports can be attached to any chassis */
#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32
-int lldp_read_chassis_id(tlv_packet *tlv,
- uint8_t *type,
- uint16_t *length,
- uint8_t **data) {
- uint8_t subtype;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID);
- if (r < 0)
- goto out2;
-
- r = tlv_packet_read_u8(tlv, &subtype);
- if (r < 0)
- goto out1;
-
- switch (subtype) {
- case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
-
- r = tlv_packet_read_bytes(tlv, data, length);
- if (r < 0)
- goto out1;
-
- break;
- default:
- r = -EOPNOTSUPP;
- break;
- }
-
- *type = subtype;
-
- out1:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- out2:
- return r;
-}
-
-int lldp_read_port_id(tlv_packet *tlv,
- uint8_t *type,
- uint16_t *length,
- uint8_t **data) {
- uint8_t subtype;
- char *s;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID);
- if (r < 0)
- goto out2;
-
- r = tlv_packet_read_u8(tlv, &subtype);
- if (r < 0)
- goto out1;
-
- switch (subtype) {
- case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
- case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
- case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
- case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out1;
-
- *data = (uint8_t *) s;
-
- break;
- case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
-
- r = tlv_packet_read_bytes(tlv, data, length);
- if (r < 0)
- goto out1;
-
- break;
- default:
- r = -EOPNOTSUPP;
- break;
- }
-
- *type = subtype;
-
- out1:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- out2:
- return r;
-}
-
-int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl) {
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_TTL);
- if (r < 0)
- goto out;
-
- r = tlv_packet_read_u16(tlv, ttl);
-
- (void) lldp_tlv_packet_exit_container(tlv);
-
- out:
- return r;
-}
-
-int lldp_read_system_name(tlv_packet *tlv,
- uint16_t *length,
- char **data) {
- char *s;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_NAME);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out;
-
- *data = (char *) s;
-
- out:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- return r;
-}
-
-int lldp_read_system_description(tlv_packet *tlv,
- uint16_t *length,
- char **data) {
- char *s;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out;
-
- *data = (char *) s;
-
- out:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- return r;
-}
-
-int lldp_read_port_description(tlv_packet *tlv,
- uint16_t *length,
- char **data) {
- char *s;
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_DESCRIPTION);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_string(tlv, &s, length);
- if (r < 0)
- goto out;
-
- *data = (char *) s;
-
- out:
- (void) lldp_tlv_packet_exit_container(tlv);
-
- return r;
-}
-
-int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data) {
- int r;
-
- assert_return(tlv, -EINVAL);
-
- r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES);
- if (r < 0)
- return r;
-
- r = tlv_packet_read_u16(tlv, data);
- if (r < 0)
- goto out;
-
- return 0;
- out:
-
- (void) lldp_tlv_packet_exit_container(tlv);
-
- return r;
-}
-
/* 10.5.5.2.2 mibUpdateObjects ()
* The mibUpdateObjects () procedure updates the MIB objects corresponding to
* the TLVs contained in the received LLDPDU for the LLDP remote system
@@ -244,7 +44,7 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) {
assert_return(c, -EINVAL);
assert_return(tlv, -EINVAL);
- r = lldp_read_port_id(tlv, &type, &length, &data);
+ r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
if (r < 0)
return r;
@@ -253,13 +53,13 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) {
if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) {
- r = lldp_read_ttl(tlv, &ttl);
+ r = sd_lldp_packet_read_ttl(tlv, &ttl);
if (r < 0)
return r;
p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
- tlv_packet_free(p->packet);
+ sd_lldp_packet_unref(p->packet);
p->packet = tlv;
prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx);
@@ -281,7 +81,7 @@ int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) {
assert_return(c, -EINVAL);
assert_return(tlv, -EINVAL);
- r = lldp_read_port_id(tlv, &type, &length, &data);
+ r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
if (r < 0)
return r;
@@ -312,11 +112,11 @@ int lldp_mib_add_objects(Prioq *by_expiry,
assert_return(neighbour_mib, -EINVAL);
assert_return(tlv, -EINVAL);
- r = lldp_read_chassis_id(tlv, &subtype, &length, &data);
+ r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length);
if (r < 0)
goto drop;
- r = lldp_read_ttl(tlv, &ttl);
+ r = sd_lldp_packet_read_ttl(tlv, &ttl);
if (r < 0)
goto drop;
@@ -401,7 +201,7 @@ int lldp_mib_add_objects(Prioq *by_expiry,
return 0;
drop:
- tlv_packet_free(tlv);
+ sd_lldp_packet_unref(tlv);
if (new_chassis)
hashmap_remove(neighbour_mib, &c->chassis_id);
@@ -435,7 +235,7 @@ void lldp_neighbour_port_free(lldp_neighbour_port *p) {
if(!p)
return;
- tlv_packet_free(p->packet);
+ sd_lldp_packet_unref(p->packet);
free(p->data);
free(p);
@@ -452,11 +252,11 @@ int lldp_neighbour_port_new(lldp_chassis *c,
assert(tlv);
- r = lldp_read_port_id(tlv, &type, &length, &data);
+ r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
if (r < 0)
return r;
- r = lldp_read_ttl(tlv, &ttl);
+ r = sd_lldp_packet_read_ttl(tlv, &ttl);
if (r < 0)
return r;
@@ -505,7 +305,7 @@ int lldp_chassis_new(tlv_packet *tlv,
assert(tlv);
- r = lldp_read_chassis_id(tlv, &type, &length, &data);
+ r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length);
if (r < 0)
return r;
@@ -531,3 +331,30 @@ int lldp_chassis_new(tlv_packet *tlv,
return 0;
}
+
+int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ _cleanup_lldp_packet_unref_ tlv_packet *packet = NULL;
+ tlv_packet *p;
+ uint16_t length;
+ int r;
+
+ assert(fd);
+ assert(userdata);
+
+ r = tlv_packet_new(&packet);
+ if (r < 0)
+ return r;
+
+ length = read(fd, &packet->pdu, sizeof(packet->pdu));
+
+ /* Silently drop the packet */
+ if ((size_t) length > ETHER_MAX_LEN)
+ return 0;
+
+ packet->userdata = userdata;
+
+ p = packet;
+ packet = NULL;
+
+ return lldp_handle_packet(p, (uint16_t) length);
+}
diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h
index f4eadbb87e..284cc6720e 100644
--- a/src/libsystemd-network/lldp-internal.h
+++ b/src/libsystemd-network/lldp-internal.h
@@ -26,6 +26,7 @@
#include "list.h"
#include "lldp-tlv.h"
#include "prioq.h"
+#include "sd-event.h"
typedef struct lldp_neighbour_port lldp_neighbour_port;
typedef struct lldp_chassis lldp_chassis;
@@ -86,13 +87,6 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv);
int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv);
int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv);
-int lldp_read_chassis_id(tlv_packet *tlv, uint8_t *type, uint16_t *length, uint8_t **data);
-int lldp_read_port_id(tlv_packet *tlv, uint8_t *type, uint16_t *length, uint8_t **data);
-int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl);
-int lldp_read_system_name(tlv_packet *tlv, uint16_t *length, char **data);
-int lldp_read_system_description(tlv_packet *tlv, uint16_t *length, char **data);
-int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data);
-int lldp_read_port_description(tlv_packet *tlv, uint16_t *length, char **data);
-
int lldp_handle_packet(tlv_packet *m, uint16_t length);
+int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata);
#define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c
index 664d2f7867..12a6599ff1 100644
--- a/src/libsystemd-network/lldp-network.c
+++ b/src/libsystemd-network/lldp-network.c
@@ -82,30 +82,3 @@ int lldp_network_bind_raw_socket(int ifindex) {
return r;
}
-
-int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- _cleanup_tlv_packet_free_ tlv_packet *packet = NULL;
- tlv_packet *p;
- uint16_t length;
- int r;
-
- assert(fd);
- assert(userdata);
-
- r = tlv_packet_new(&packet);
- if (r < 0)
- return r;
-
- length = read(fd, &packet->pdu, sizeof(packet->pdu));
-
- /* Silently drop the packet */
- if ((size_t) length > ETHER_MAX_LEN)
- return 0;
-
- packet->userdata = userdata;
-
- p = packet;
- packet = NULL;
-
- return lldp_handle_packet(p, (uint16_t) length);
-}
diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h
index b7f8d3bf80..74ee13a414 100644
--- a/src/libsystemd-network/lldp-network.h
+++ b/src/libsystemd-network/lldp-network.h
@@ -25,4 +25,3 @@
#include "sd-event.h"
int lldp_network_bind_raw_socket(int ifindex);
-int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata);
diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c
index aa6a3b9224..7486b4c38f 100644
--- a/src/libsystemd-network/lldp-port.c
+++ b/src/libsystemd-network/lldp-port.c
@@ -23,6 +23,7 @@
#include "async.h"
#include "lldp-port.h"
#include "lldp-network.h"
+#include "lldp-internal.h"
int lldp_port_start(lldp_port *p) {
int r;
@@ -38,19 +39,19 @@ int lldp_port_start(lldp_port *p) {
r = sd_event_add_io(p->event, &p->lldp_port_rx,
p->rawfd, EPOLLIN, lldp_receive_packet, p);
if (r < 0) {
- log_debug("Failed to allocate event source: %s", strerror(-r));
- return r;
+ log_debug_errno(r, "Failed to allocate event source: %m");
+ goto fail;
}
r = sd_event_source_set_priority(p->lldp_port_rx, p->event_priority);
if (r < 0) {
- log_debug("Failed to set event priority: %s", strerror(-r));
+ log_debug_errno(r, "Failed to set event priority: %m");
goto fail;
}
r = sd_event_source_set_description(p->lldp_port_rx, "lldp-port-rx");
if (r < 0) {
- log_debug("Failed to set event name: %s", strerror(-r));
+ log_debug_errno(r, "Failed to set event name: %m");
goto fail;
}
diff --git a/src/libsystemd-network/lldp-port.h b/src/libsystemd-network/lldp-port.h
index b2d3180091..517b162a67 100644
--- a/src/libsystemd-network/lldp-port.h
+++ b/src/libsystemd-network/lldp-port.h
@@ -31,6 +31,14 @@
typedef struct lldp_port lldp_port;
+typedef enum LLDPPortStatus {
+ LLDP_PORT_STATUS_NONE,
+ LLDP_PORT_STATUS_ENABLED,
+ LLDP_PORT_STATUS_DISABLED,
+ _LLDP_PORT_STATUS_MAX,
+ _LLDP_PORT_STATUS_INVALID = -1,
+} LLDPPortStatus;
+
struct lldp_port {
LLDPPortStatus status;
diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c
index 0cea5b10a6..66af22e37d 100644
--- a/src/libsystemd-network/lldp-tlv.c
+++ b/src/libsystemd-network/lldp-tlv.c
@@ -54,22 +54,41 @@ int tlv_packet_new(tlv_packet **ret) {
return -ENOMEM;
LIST_HEAD_INIT(m->sections);
+ m->n_ref = 1;
*ret = m;
return 0;
}
-void tlv_packet_free(tlv_packet *m) {
+tlv_packet *sd_lldp_packet_ref(tlv_packet *m) {
+
+ if (!m)
+ return NULL;
+
+ assert(m->n_ref > 0);
+ m->n_ref++;
+
+ return m;
+}
+
+tlv_packet *sd_lldp_packet_unref(tlv_packet *m) {
tlv_section *s, *n;
if (!m)
- return;
+ return NULL;
+
+ assert(m->n_ref > 0);
+ m->n_ref--;
+
+ if (m->n_ref > 0)
+ return m;
LIST_FOREACH_SAFE(section, s, n, m->sections)
tlv_section_free(s);
free(m);
+ return NULL;
}
int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) {
@@ -221,9 +240,9 @@ int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) {
return r;
*data = (char *) val;
- *data_length = m->container->length;
+ *data_length = m->container->data + m->container->length - m->container->read_pos;
- m->container->read_pos += m->container->length;
+ m->container->read_pos += *data_length;
return 0;
}
@@ -239,9 +258,9 @@ int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length)
return r;
*data = (uint8_t *) val;
- *data_length = m->container->length;
+ *data_length = m->container->data + m->container->length - m->container->read_pos;
- m->container->read_pos += m->container->length;
+ m->container->read_pos += *data_length;
return 0;
}
@@ -258,7 +277,7 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
p = m->pdu;
- /* extract ethernet herader */
+ /* extract ethernet header */
memcpy(&m->mac, p, ETH_ALEN);
p += sizeof(struct ether_header);
@@ -278,6 +297,17 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
}
p += 2;
+
+ if (section->type == LLDP_TYPE_PRIVATE &&
+ section->length >= LLDP_OUI_LEN + 1) {
+ section->oui = p;
+ p += LLDP_OUI_LEN;
+ section->subtype = *p++;
+
+ section->length -= LLDP_OUI_LEN + 1;
+ l += LLDP_OUI_LEN + 1;
+ }
+
section->data = p;
LIST_FIND_TAIL(section, m->sections, tail);
@@ -294,6 +324,7 @@ int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) {
tlv_section *s;
assert_return(m, -EINVAL);
+ assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL);
LIST_FOREACH(section, s, m->sections)
if (s->type == type)
@@ -305,7 +336,35 @@ int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) {
m->container->read_pos = s->data;
if (!m->container->read_pos) {
- m->container = 0;
+ m->container = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) {
+ tlv_section *s;
+
+ assert_return(m, -EINVAL);
+ assert_return(oui, -EINVAL);
+
+ LIST_FOREACH(section, s, m->sections) {
+ if (s->type == LLDP_TYPE_PRIVATE &&
+ s->oui &&
+ s->subtype == subtype &&
+ !memcmp(s->oui, oui, LLDP_OUI_LEN))
+ break;
+ }
+
+ if (!s)
+ return -1;
+
+ m->container = s;
+
+ m->container->read_pos = s->data;
+ if (!m->container->read_pos) {
+ m->container = NULL;
return -1;
}
@@ -319,3 +378,270 @@ int lldp_tlv_packet_exit_container(tlv_packet *m) {
return 0;
}
+
+static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container(tlv, type);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u16(tlv, value);
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+static int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) {
+ char *s;
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container(tlv, type);
+ if (r < 0)
+ return r;
+
+ r = tlv_packet_read_string(tlv, &s, length);
+ if (r < 0)
+ goto out;
+
+ *data = (char *) s;
+
+ out:
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_chassis_id(tlv_packet *tlv,
+ uint8_t *type,
+ uint8_t **data,
+ uint16_t *length) {
+ uint8_t subtype;
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID);
+ if (r < 0)
+ goto out2;
+
+ r = tlv_packet_read_u8(tlv, &subtype);
+ if (r < 0)
+ goto out1;
+
+ switch (subtype) {
+ case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
+
+ r = tlv_packet_read_bytes(tlv, data, length);
+ if (r < 0)
+ goto out1;
+
+ break;
+ default:
+ r = -EOPNOTSUPP;
+ break;
+ }
+
+ *type = subtype;
+
+ out1:
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out2:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_port_id(tlv_packet *tlv,
+ uint8_t *type,
+ uint8_t **data,
+ uint16_t *length) {
+ uint8_t subtype;
+ char *s;
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID);
+ if (r < 0)
+ goto out2;
+
+ r = tlv_packet_read_u8(tlv, &subtype);
+ if (r < 0)
+ goto out1;
+
+ switch (subtype) {
+ case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
+ case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
+ case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
+ case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
+
+ r = tlv_packet_read_string(tlv, &s, length);
+ if (r < 0)
+ goto out1;
+
+ *data = (uint8_t *) s;
+
+ break;
+ case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
+
+ r = tlv_packet_read_bytes(tlv, data, length);
+ if (r < 0)
+ goto out1;
+
+ break;
+ default:
+ r = -EOPNOTSUPP;
+ break;
+ }
+
+ *type = subtype;
+
+ out1:
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out2:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) {
+ return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl);
+}
+
+int sd_lldp_packet_read_system_name(tlv_packet *tlv,
+ char **data,
+ uint16_t *length) {
+ return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length);
+}
+
+int sd_lldp_packet_read_system_description(tlv_packet *tlv,
+ char **data,
+ uint16_t *length) {
+ return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length);
+}
+
+int sd_lldp_packet_read_port_description(tlv_packet *tlv,
+ char **data,
+ uint16_t *length) {
+ return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length);
+}
+
+int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) {
+ return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data);
+}
+
+int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u16(tlv, id);
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u8(tlv, flags);
+ if (r >= 0)
+ r = tlv_packet_read_u16(tlv, id);
+
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) {
+ int r, r2;
+ uint8_t len = 0;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u16(tlv, vlan_id);
+ if (r >= 0)
+ r = tlv_packet_read_u8(tlv, &len);
+ if (r >= 0)
+ r = tlv_packet_read_string(tlv, name, length);
+
+ if (r >= 0 && len < *length)
+ *length = len;
+
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u16(tlv, id);
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) {
+ int r, r2;
+
+ assert_return(tlv, -EINVAL);
+
+ r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION);
+ if (r < 0)
+ goto out;
+
+ r = tlv_packet_read_u8(tlv, status);
+ if (r >= 0)
+ r = tlv_packet_read_u32(tlv, id);
+
+ r2 = lldp_tlv_packet_exit_container(tlv);
+
+ out:
+ return r < 0 ? r : r2;
+}
+
+int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) {
+ assert_return(tlv, -EINVAL);
+ assert_return(dest, -EINVAL);
+
+ /* 802.1AB-2009, Table 7-1 */
+ if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN))
+ *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE;
+ else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN))
+ *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE;
+ else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN))
+ *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE;
+ else
+ return -EINVAL;
+
+ return 0;
+}
diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h
index ce3334e115..ca1da113d5 100644
--- a/src/libsystemd-network/lldp-tlv.h
+++ b/src/libsystemd-network/lldp-tlv.h
@@ -28,12 +28,18 @@
#include "lldp.h"
#include "list.h"
-typedef struct tlv_packet tlv_packet;
-typedef struct tlv_section tlv_section;
+#include "sd-lldp.h"
-struct tlv_section {
+typedef struct sd_lldp_packet tlv_packet;
+typedef struct sd_lldp_section tlv_section;
+
+#define LLDP_OUI_LEN 3
+
+struct sd_lldp_section {
uint16_t type;
uint16_t length;
+ uint8_t *oui;
+ uint8_t subtype;
uint8_t *read_pos;
uint8_t *data;
@@ -41,10 +47,16 @@ struct tlv_section {
LIST_FIELDS(tlv_section, section);
};
+#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
+#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }
+#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }
+
int tlv_section_new(tlv_section **ret);
void tlv_section_free(tlv_section *ret);
-struct tlv_packet {
+struct sd_lldp_packet {
+ unsigned n_ref;
+
uint16_t type;
uint16_t length;
usec_t ts;
@@ -61,10 +73,9 @@ struct tlv_packet {
};
int tlv_packet_new(tlv_packet **ret);
-void tlv_packet_free(tlv_packet *m);
-DEFINE_TRIVIAL_CLEANUP_FUNC(tlv_packet*, tlv_packet_free);
-#define _cleanup_tlv_packet_free_ _cleanup_(tlv_packet_freep)
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_lldp_packet*, sd_lldp_packet_unref);
+#define _cleanup_lldp_packet_unref_ _cleanup_(sd_lldp_packet_unrefp)
int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type);
int lldp_tlv_packet_close_container(tlv_packet *m);
@@ -76,6 +87,7 @@ int tlv_packet_append_u32(tlv_packet *m, uint32_t data);
int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size);
int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type);
+int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype);
int lldp_tlv_packet_exit_container(tlv_packet *m);
int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length);
diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h
index 5e4b283e26..19e5cc5f41 100644
--- a/src/libsystemd-network/lldp.h
+++ b/src/libsystemd-network/lldp.h
@@ -113,3 +113,16 @@ typedef enum LLDPMedCapability {
LLDP_MED_CAPABILITY_MAX,
LLDP_MED_CAPABILITY_INVALID = -1,
} LLDPMedCapability;
+
+#define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 }
+#define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f }
+
+enum {
+ LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1,
+ LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2,
+ LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3,
+ LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4,
+ LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5,
+ LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6,
+ LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7,
+};
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 26bd4088d9..2a62af2fd4 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -196,8 +196,7 @@ int config_parse_ifname(const char *unit,
return log_oom();
if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
return 0;
}
@@ -240,8 +239,7 @@ int config_parse_ifnames(const char *unit,
return log_oom();
if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
free(n);
return 0;
}
@@ -278,8 +276,7 @@ int config_parse_ifalias(const char *unit,
return log_oom();
if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
return 0;
}
@@ -324,8 +321,7 @@ int config_parse_hwaddr(const char *unit,
&n->ether_addr_octet[4],
&n->ether_addr_octet[5]);
if (r != 6) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Not a valid MAC address, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
free(n);
return 0;
}
@@ -394,8 +390,8 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
assert(size);
for (i = 0; i < size; i++)
- fprintf(f, SD_ICMP6_ADDRESS_FORMAT_STR"%s",
- SD_ICMP6_ADDRESS_FORMAT_VAL(addresses[i]),
+ fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s",
+ SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]),
(i < (size - 1)) ? " ": "");
}
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index c12768cf0e..28e012afca 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -213,7 +213,7 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
log_dhcp_client(client, "Changing MAC address on running DHCP "
"client, restarting");
need_restart = true;
- client_stop(client, DHCP_EVENT_STOP);
+ client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
}
memcpy(&client->mac_addr, addr, addr_len);
@@ -277,7 +277,7 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
log_dhcp_client(client, "Changing client ID on running DHCP "
"client, restarting");
need_restart = true;
- client_stop(client, DHCP_EVENT_STOP);
+ client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
}
client->client_id.type = type;
@@ -385,7 +385,7 @@ static void client_stop(sd_dhcp_client *client, int error) {
if (error < 0)
log_dhcp_client(client, "STOPPED: %s", strerror(-error));
- else if (error == DHCP_EVENT_STOP)
+ else if (error == SD_DHCP_CLIENT_EVENT_STOP)
log_dhcp_client(client, "STOPPED");
else
log_dhcp_client(client, "STOPPED: Unknown event");
@@ -983,7 +983,7 @@ static int client_timeout_expire(sd_event_source *s, uint64_t usec,
log_dhcp_client(client, "EXPIRED");
- client_notify(client, DHCP_EVENT_EXPIRED);
+ client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED);
/* lease was lost, start over if not freed or stopped in callback */
if (client->state != DHCP_STATE_STOPPED) {
@@ -1143,14 +1143,14 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
}
}
- r = DHCP_EVENT_IP_ACQUIRE;
+ r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
if (client->lease) {
if (client->lease->address != lease->address ||
client->lease->subnet_mask != lease->subnet_mask ||
client->lease->router != lease->router) {
- r = DHCP_EVENT_IP_CHANGE;
+ r = SD_DHCP_CLIENT_EVENT_IP_CHANGE;
} else
- r = DHCP_EVENT_RENEW;
+ r = SD_DHCP_CLIENT_EVENT_RENEW;
client->lease = sd_dhcp_lease_unref(client->lease);
}
@@ -1265,8 +1265,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
log_dhcp_client(client, "lease expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- lifetime_timeout - time_now, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC));
/* don't arm earlier timeouts if this has already expired */
if (lifetime_timeout <= time_now)
@@ -1292,8 +1291,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
log_dhcp_client(client, "T2 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- t2_timeout - time_now, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC));
/* don't arm earlier timeout if this has already expired */
if (t2_timeout <= time_now)
@@ -1318,8 +1316,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return r;
log_dhcp_client(client, "T1 expires in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- t1_timeout - time_now, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC));
return 0;
}
@@ -1382,8 +1379,8 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
if (IN_SET(client->state, DHCP_STATE_REQUESTING,
DHCP_STATE_REBOOTING))
- notify_event = DHCP_EVENT_IP_ACQUIRE;
- else if (r != DHCP_EVENT_IP_ACQUIRE)
+ notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE;
+ else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE)
notify_event = r;
client->state = DHCP_STATE_BOUND;
@@ -1633,7 +1630,7 @@ int sd_dhcp_client_stop(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
- client_stop(client, DHCP_EVENT_STOP);
+ client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
client->state = DHCP_STATE_STOPPED;
return 0;
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index aa07846693..df3d8e6e3c 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -314,10 +314,14 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
else {
char *string;
- if (memchr(option, 0, len))
+ /*
+ * One trailing NUL byte is OK, we don't mind. See:
+ * https://github.com/systemd/systemd/issues/1337
+ */
+ if (memchr(option, 0, len - 1))
return -EINVAL;
- string = strndup((const char *)option, len);
+ string = strndup((const char *) option, len);
if (!string)
return -ENOMEM;
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index 1f167485e3..d27bb561ca 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -110,18 +110,15 @@ sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) {
return server;
}
-unsigned long client_id_hash_func(const void *p,
- const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
+void client_id_hash_func(const void *p, struct siphash *state) {
const DHCPClientId *id = p;
assert(id);
assert(id->length);
assert(id->data);
- siphash24((uint8_t*) &u, id->data, id->length, hash_key);
-
- return (unsigned long) u;
+ siphash24_compress(&id->length, sizeof(id->length), state);
+ siphash24_compress(id->data, id->length, state);
}
int client_id_compare_func(const void *_a, const void *_b) {
@@ -743,13 +740,18 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message,
if (existing_lease)
address = existing_lease->address;
else {
+ struct siphash state;
+ uint64_t hash;
uint32_t next_offer;
/* even with no persistence of leases, we try to offer the same client
the same IP address. we do this by using the hash of the client id
as the offset into the pool of leases when finding the next free one */
- next_offer = client_id_hash_func(&req->client_id, HASH_KEY.bytes) % server->pool_size;
+ siphash24_init(&state, HASH_KEY.bytes);
+ client_id_hash_func(&req->client_id, &state);
+ siphash24_finalize((uint8_t*)&hash, &state);
+ next_offer = hash % server->pool_size;
for (i = 0; i < server->pool_size; i++) {
if (!server->bound_leases[next_offer]) {
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 5489c77864..9cd4bd3032 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -125,6 +125,8 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
assert_return(client, -EINVAL);
assert_return(interface_index >= -1, -EINVAL);
+ assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
client->index = interface_index;
return 0;
@@ -140,6 +142,8 @@ int sd_dhcp6_client_set_mac(
assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL);
assert_return(arp_type > 0, -EINVAL);
+ assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
if (arp_type == ARPHRD_ETHER)
assert_return(addr_len == ETH_ALEN, -EINVAL);
else if (arp_type == ARPHRD_INFINIBAND)
@@ -173,6 +177,8 @@ int sd_dhcp6_client_set_duid(
assert_return(duid, -EINVAL);
assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
+ assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
switch (type) {
case DHCP6_DUID_LLT:
if (duid_len <= sizeof(client->duid.llt))
@@ -205,6 +211,8 @@ int sd_dhcp6_client_set_duid(
int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enabled) {
assert_return(client, -EINVAL);
+ assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
client->information_request = enabled;
return 0;
@@ -266,13 +274,18 @@ static void client_notify(sd_dhcp6_client *client, int event) {
client->cb(client, event, client->userdata);
}
-static int client_reset(sd_dhcp6_client *client) {
- assert_return(client, -EINVAL);
-
+static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) {
if (client->lease) {
dhcp6_lease_clear_timers(&client->lease->ia);
- client->lease = sd_dhcp6_lease_unref(client->lease);
+ sd_dhcp6_lease_unref(client->lease);
}
+ client->lease = lease;
+}
+
+static int client_reset(sd_dhcp6_client *client) {
+ assert_return(client, -EINVAL);
+
+ client_set_lease(client, NULL);
client->receive_message =
sd_event_source_unref(client->receive_message);
@@ -464,7 +477,7 @@ static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
state = client->state;
- client_stop(client, DHCP6_EVENT_RESEND_EXPIRE);
+ client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE);
/* RFC 3315, section 18.1.4., says that "...the client may choose to
use a Solicit message to locate a new DHCP server..." */
@@ -554,7 +567,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
if (max_retransmit_count &&
client->retransmit_count >= max_retransmit_count) {
- client_stop(client, DHCP6_EVENT_RETRANS_MAX);
+ client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX);
return 0;
}
@@ -582,8 +595,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec,
}
log_dhcp6_client(client, "Next retransmission in %s",
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- client->retransmit_time, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC));
r = sd_event_add_time(client->event, &client->timeout_resend,
clock_boottime_or_monotonic(),
@@ -826,12 +838,7 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si
return 0;
}
- if (client->lease) {
- dhcp6_lease_clear_timers(&client->lease->ia);
- client->lease = sd_dhcp6_lease_unref(client->lease);
- }
-
- client->lease = lease;
+ client_set_lease(client, lease);
lease = NULL;
return DHCP6_STATE_BOUND;
@@ -860,8 +867,7 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver
r = dhcp6_lease_get_preference(client->lease, &pref_lease);
if (r < 0 || pref_advertise > pref_lease) {
- sd_dhcp6_lease_unref(client->lease);
- client->lease = lease;
+ client_set_lease(client, lease);
lease = NULL;
r = 0;
}
@@ -930,7 +936,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
if (r < 0)
return 0;
- client_notify(client, DHCP6_EVENT_INFORMATION_REQUEST);
+ client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
client_start(client, DHCP6_STATE_STOPPED);
@@ -962,7 +968,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
return 0;
}
- client_notify(client, DHCP6_EVENT_IP_ACQUIRE);
+ client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
}
break;
@@ -1041,9 +1047,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC);
log_dhcp6_client(client, "T1 expires in %s",
- format_timespan(time_string,
- FORMAT_TIMESPAN_MAX,
- timeout, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t1,
@@ -1065,9 +1069,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC);
log_dhcp6_client(client, "T2 expires in %s",
- format_timespan(time_string,
- FORMAT_TIMESPAN_MAX,
- timeout, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC));
r = sd_event_add_time(client->event,
&client->lease->ia.timeout_t2,
@@ -1113,7 +1115,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
}
int sd_dhcp6_client_stop(sd_dhcp6_client *client) {
- client_stop(client, DHCP6_EVENT_STOP);
+ client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP);
return 0;
}
@@ -1126,6 +1128,9 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
assert_return(client->event, -EINVAL);
assert_return(client->index > 0, -EINVAL);
+ if (!IN_SET(client->state, DHCP6_STATE_STOPPED))
+ return -EALREADY;
+
r = client_reset(client);
if (r < 0)
return r;
@@ -1233,7 +1238,6 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) {
client_reset(client);
sd_dhcp6_client_detach_event(client);
- sd_dhcp6_lease_unref(client->lease);
free(client->req_opts);
free(client);
diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c
index e80232a7e0..f014cac628 100644
--- a/src/libsystemd-network/sd-icmp6-nd.c
+++ b/src/libsystemd-network/sd-icmp6-nd.c
@@ -274,15 +274,15 @@ static int icmp6_ra_prefix_timeout(sd_event_source *s, uint64_t usec,
if (prefix->timeout_valid != s)
continue;
- log_icmp6_nd(nd, "Prefix expired "SD_ICMP6_ADDRESS_FORMAT_STR"/%d",
- SD_ICMP6_ADDRESS_FORMAT_VAL(prefix->addr),
+ log_icmp6_nd(nd, "Prefix expired "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d",
+ SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
prefix->len);
LIST_REMOVE(prefixes, nd->prefixes, prefix);
nd->expired_prefix = prefix;
icmp6_nd_notify(nd,
- ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED);
+ SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED);
nd->expired_prefix = NULL;
prefix = icmp6_prefix_unref(prefix);
@@ -441,11 +441,10 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix,
sizeof(prefix->addr));
- log_icmp6_nd(nd, "New prefix "SD_ICMP6_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
- SD_ICMP6_ADDRESS_FORMAT_VAL(prefix->addr),
+ log_icmp6_nd(nd, "New prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
+ SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
prefix->len, lifetime,
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- lifetime * USEC_PER_SEC, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC));
LIST_PREPEND(prefixes, nd->prefixes, prefix);
@@ -463,11 +462,10 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len,
prefix->len = prefixlen;
}
- log_icmp6_nd(nd, "Update prefix "SD_ICMP6_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
- SD_ICMP6_ADDRESS_FORMAT_VAL(prefix->addr),
+ log_icmp6_nd(nd, "Update prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s",
+ SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr),
prefix->len, lifetime,
- format_timespan(time_string, FORMAT_TIMESPAN_MAX,
- lifetime * USEC_PER_SEC, 0));
+ format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC));
}
r = icmp6_ra_prefix_set_timeout(nd, prefix, lifetime * USEC_PER_SEC);
@@ -541,7 +539,7 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
int r, buflen = 0;
ssize_t len;
_cleanup_free_ struct nd_router_advert *ra = NULL;
- int event = ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE;
+ int event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE;
assert(s);
assert(nd);
@@ -572,16 +570,16 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r
nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN;
if (ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER )
- event = ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER;
+ event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER;
if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
- event = ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED;
+ event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED;
log_icmp6_nd(nd, "Received Router Advertisement flags %s/%s",
ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED? "MANAGED": "none",
ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER? "OTHER": "none");
- if (event != ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE) {
+ if (event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE) {
r = icmp6_ra_parse(nd, ra, len);
if (r < 0) {
log_icmp6_nd(nd, "Could not parse Router Advertisement: %s",
@@ -609,7 +607,7 @@ static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec,
nd->timeout = sd_event_source_unref(nd->timeout);
if (nd->nd_sent >= ICMP6_MAX_ROUTER_SOLICITATIONS) {
- icmp6_nd_notify(nd, ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT);
+ icmp6_nd_notify(nd, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT);
nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN;
} else {
if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr)))
diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c
new file mode 100644
index 0000000000..95b96bfd52
--- /dev/null
+++ b/src/libsystemd-network/sd-ipv4acd.c
@@ -0,0 +1,529 @@
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Axis Communications AB. All rights reserved.
+ Copyright (C) 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "event-util.h"
+#include "in-addr-util.h"
+#include "list.h"
+#include "refcnt.h"
+#include "random-util.h"
+#include "siphash24.h"
+#include "util.h"
+
+#include "arp-util.h"
+#include "sd-ipv4acd.h"
+
+/* Constants from the RFC */
+#define PROBE_WAIT 1
+#define PROBE_NUM 3
+#define PROBE_MIN 1
+#define PROBE_MAX 2
+#define ANNOUNCE_WAIT 2
+#define ANNOUNCE_NUM 2
+#define ANNOUNCE_INTERVAL 2
+#define MAX_CONFLICTS 10
+#define RATE_LIMIT_INTERVAL 60
+#define DEFEND_INTERVAL 10
+
+#define IPV4ACD_NETWORK 0xA9FE0000L
+#define IPV4ACD_NETMASK 0xFFFF0000L
+
+#define log_ipv4acd_full(ll, level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__)
+
+#define log_ipv4acd_debug(ll, ...) log_ipv4acd_full(ll, LOG_DEBUG, 0, ##__VA_ARGS__)
+#define log_ipv4acd_info(ll, ...) log_ipv4acd_full(ll, LOG_INFO, 0, ##__VA_ARGS__)
+#define log_ipv4acd_notice(ll, ...) log_ipv4acd_full(ll, LOG_NOTICE, 0, ##__VA_ARGS__)
+#define log_ipv4acd_warning(ll, ...) log_ipv4acd_full(ll, LOG_WARNING, 0, ##__VA_ARGS__)
+#define log_ipv4acd_error(ll, ...) log_ipv4acd_full(ll, LOG_ERR, 0, ##__VA_ARGS__)
+
+#define log_ipv4acd_debug_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_DEBUG, error, ##__VA_ARGS__)
+#define log_ipv4acd_info_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_INFO, error, ##__VA_ARGS__)
+#define log_ipv4acd_notice_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_NOTICE, error, ##__VA_ARGS__)
+#define log_ipv4acd_warning_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_WARNING, error, ##__VA_ARGS__)
+#define log_ipv4acd_error_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_ERR, error, ##__VA_ARGS__)
+
+typedef enum IPv4ACDState {
+ IPV4ACD_STATE_INIT,
+ IPV4ACD_STATE_WAITING_PROBE,
+ IPV4ACD_STATE_PROBING,
+ IPV4ACD_STATE_WAITING_ANNOUNCE,
+ IPV4ACD_STATE_ANNOUNCING,
+ IPV4ACD_STATE_RUNNING,
+ _IPV4ACD_STATE_MAX,
+ _IPV4ACD_STATE_INVALID = -1
+} IPv4ACDState;
+
+struct sd_ipv4acd {
+ RefCount n_ref;
+
+ IPv4ACDState state;
+ int index;
+ int fd;
+ int iteration;
+ int conflict;
+ sd_event_source *receive_message;
+ sd_event_source *timer;
+ usec_t defend_window;
+ be32_t address;
+ /* External */
+ struct ether_addr mac_addr;
+ sd_event *event;
+ int event_priority;
+ sd_ipv4acd_cb_t cb;
+ void* userdata;
+};
+
+sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll) {
+ if (ll)
+ assert_se(REFCNT_INC(ll->n_ref) >= 2);
+
+ return ll;
+}
+
+sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) {
+ if (!ll || REFCNT_DEC(ll->n_ref) > 0)
+ return NULL;
+
+ ll->receive_message = sd_event_source_unref(ll->receive_message);
+ ll->fd = safe_close(ll->fd);
+
+ ll->timer = sd_event_source_unref(ll->timer);
+
+ sd_ipv4acd_detach_event(ll);
+
+ free(ll);
+
+ return NULL;
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4acd*, sd_ipv4acd_unref);
+#define _cleanup_ipv4acd_unref_ _cleanup_(sd_ipv4acd_unrefp)
+
+int sd_ipv4acd_new(sd_ipv4acd **ret) {
+ _cleanup_ipv4acd_unref_ sd_ipv4acd *ll = NULL;
+
+ assert_return(ret, -EINVAL);
+
+ ll = new0(sd_ipv4acd, 1);
+ if (!ll)
+ return -ENOMEM;
+
+ ll->n_ref = REFCNT_INIT;
+ ll->state = IPV4ACD_STATE_INIT;
+ ll->index = -1;
+ ll->fd = -1;
+
+ *ret = ll;
+ ll = NULL;
+
+ return 0;
+}
+
+static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) {
+
+ assert(ll);
+ assert(st < _IPV4ACD_STATE_MAX);
+
+ if (st == ll->state && !reset_counter)
+ ll->iteration++;
+ else {
+ ll->state = st;
+ ll->iteration = 0;
+ }
+}
+
+static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) {
+ assert(ll);
+
+ if (ll->cb)
+ ll->cb(ll, event, ll->userdata);
+}
+
+static void ipv4acd_stop(sd_ipv4acd *ll) {
+ assert(ll);
+
+ ll->receive_message = sd_event_source_unref(ll->receive_message);
+ ll->fd = safe_close(ll->fd);
+
+ ll->timer = sd_event_source_unref(ll->timer);
+
+ log_ipv4acd_debug(ll, "STOPPED");
+
+ ipv4acd_set_state (ll, IPV4ACD_STATE_INIT, true);
+}
+
+int sd_ipv4acd_stop(sd_ipv4acd *ll) {
+ assert_return(ll, -EINVAL);
+
+ ipv4acd_stop(ll);
+
+ ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_STOP);
+
+ return 0;
+}
+
+static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
+
+static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) {
+ _cleanup_event_source_unref_ sd_event_source *timer = NULL;
+ usec_t next_timeout;
+ usec_t time_now;
+ int r;
+
+ assert(sec >= 0);
+ assert(random_sec >= 0);
+ assert(ll);
+
+ next_timeout = sec * USEC_PER_SEC;
+
+ if (random_sec)
+ next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
+
+ assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+
+ r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(),
+ time_now + next_timeout, 0, ipv4acd_on_timeout, ll);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(timer, ll->event_priority);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_description(timer, "ipv4acd-timer");
+ if (r < 0)
+ return r;
+
+ ll->timer = sd_event_source_unref(ll->timer);
+ ll->timer = timer;
+ timer = NULL;
+
+ return 0;
+}
+
+static bool ipv4acd_arp_conflict(sd_ipv4acd *ll, struct ether_arp *arp) {
+ assert(ll);
+ assert(arp);
+
+ /* see the BPF */
+ if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0)
+ return true;
+
+ /* the TPA matched instead of the SPA, this is not a conflict */
+ return false;
+}
+
+static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ sd_ipv4acd *ll = userdata;
+ int r = 0;
+
+ assert(ll);
+
+ switch (ll->state) {
+ case IPV4ACD_STATE_INIT:
+
+ ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true);
+
+ if (ll->conflict >= MAX_CONFLICTS) {
+ log_ipv4acd_notice(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL);
+ r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
+ if (r < 0)
+ goto out;
+
+ ll->conflict = 0;
+ } else {
+ r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT);
+ if (r < 0)
+ goto out;
+ }
+
+ break;
+ case IPV4ACD_STATE_WAITING_PROBE:
+ case IPV4ACD_STATE_PROBING:
+ /* Send a probe */
+ r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr);
+ if (r < 0) {
+ log_ipv4acd_error_errno(ll, r, "Failed to send ARP probe: %m");
+ goto out;
+ } else {
+ _cleanup_free_ char *address = NULL;
+ union in_addr_union addr = { .in.s_addr = ll->address };
+
+ r = in_addr_to_string(AF_INET, &addr, &address);
+ if (r >= 0)
+ log_ipv4acd_debug(ll, "Probing %s", address);
+ }
+
+ if (ll->iteration < PROBE_NUM - 2) {
+ ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false);
+
+ r = ipv4acd_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
+ if (r < 0)
+ goto out;
+ } else {
+ ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
+
+ r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
+ if (r < 0)
+ goto out;
+ }
+
+ break;
+
+ case IPV4ACD_STATE_ANNOUNCING:
+ if (ll->iteration >= ANNOUNCE_NUM - 1) {
+ ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false);
+
+ break;
+ }
+ case IPV4ACD_STATE_WAITING_ANNOUNCE:
+ /* Send announcement packet */
+ r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
+ if (r < 0) {
+ log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m");
+ goto out;
+ } else
+ log_ipv4acd_debug(ll, "ANNOUNCE");
+
+ ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false);
+
+ r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
+ if (r < 0)
+ goto out;
+
+ if (ll->iteration == 0) {
+ ll->conflict = 0;
+ ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_BIND);
+ }
+
+ break;
+ default:
+ assert_not_reached("Invalid state.");
+ }
+
+out:
+ if (r < 0)
+ sd_ipv4acd_stop(ll);
+
+ return 1;
+}
+
+static void ipv4acd_on_conflict(sd_ipv4acd *ll) {
+ _cleanup_free_ char *address = NULL;
+ union in_addr_union addr = { .in.s_addr = ll->address };
+ int r;
+
+ assert(ll);
+
+ ll->conflict++;
+
+ r = in_addr_to_string(AF_INET, &addr, &address);
+ if (r >= 0)
+ log_ipv4acd_debug(ll, "Conflict on %s (%u)", address, ll->conflict);
+
+ ipv4acd_stop(ll);
+
+ ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT);
+}
+
+static int ipv4acd_on_packet(sd_event_source *s, int fd,
+ uint32_t revents, void *userdata) {
+ sd_ipv4acd *ll = userdata;
+ struct ether_arp packet;
+ int r;
+
+ assert(ll);
+ assert(fd >= 0);
+
+ r = read(fd, &packet, sizeof(struct ether_arp));
+ if (r < (int) sizeof(struct ether_arp))
+ goto out;
+
+ switch (ll->state) {
+ case IPV4ACD_STATE_ANNOUNCING:
+ case IPV4ACD_STATE_RUNNING:
+ if (ipv4acd_arp_conflict(ll, &packet)) {
+ usec_t ts;
+
+ assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &ts) >= 0);
+
+ /* Defend address */
+ if (ts > ll->defend_window) {
+ ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC;
+ r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
+ if (r < 0) {
+ log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m");
+ goto out;
+ } else
+ log_ipv4acd_debug(ll, "DEFEND");
+
+ } else
+ ipv4acd_on_conflict(ll);
+ }
+
+ break;
+ case IPV4ACD_STATE_WAITING_PROBE:
+ case IPV4ACD_STATE_PROBING:
+ case IPV4ACD_STATE_WAITING_ANNOUNCE:
+ /* BPF ensures this packet indicates a conflict */
+ ipv4acd_on_conflict(ll);
+
+ break;
+ default:
+ assert_not_reached("Invalid state.");
+ }
+
+out:
+ if (r < 0)
+ sd_ipv4acd_stop(ll);
+
+ return 1;
+}
+
+int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index) {
+ assert_return(ll, -EINVAL);
+ assert_return(interface_index > 0, -EINVAL);
+ assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
+
+ ll->index = interface_index;
+
+ return 0;
+}
+
+int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr) {
+ assert_return(ll, -EINVAL);
+ assert_return(addr, -EINVAL);
+ assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
+
+ memcpy(&ll->mac_addr, addr, ETH_ALEN);
+
+ return 0;
+}
+
+int sd_ipv4acd_detach_event(sd_ipv4acd *ll) {
+ assert_return(ll, -EINVAL);
+
+ ll->event = sd_event_unref(ll->event);
+
+ return 0;
+}
+
+int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) {
+ int r;
+
+ assert_return(ll, -EINVAL);
+ assert_return(!ll->event, -EBUSY);
+
+ if (event)
+ ll->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&ll->event);
+ if (r < 0)
+ return r;
+ }
+
+ ll->event_priority = priority;
+
+ return 0;
+}
+
+int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) {
+ assert_return(ll, -EINVAL);
+
+ ll->cb = cb;
+ ll->userdata = userdata;
+
+ return 0;
+}
+
+int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){
+ assert_return(ll, -EINVAL);
+ assert_return(address, -EINVAL);
+ assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
+
+ ll->address = address->s_addr;
+
+ return 0;
+}
+
+bool sd_ipv4acd_is_running(sd_ipv4acd *ll) {
+ assert_return(ll, false);
+
+ return ll->state != IPV4ACD_STATE_INIT;
+}
+
+static bool ether_addr_is_nul(const struct ether_addr *addr) {
+ const struct ether_addr nul_addr = {};
+
+ assert(addr);
+
+ return memcmp(addr, &nul_addr, sizeof(struct ether_addr)) == 0;
+}
+
+#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
+
+int sd_ipv4acd_start(sd_ipv4acd *ll) {
+ int r;
+
+ assert_return(ll, -EINVAL);
+ assert_return(ll->event, -EINVAL);
+ assert_return(ll->index > 0, -EINVAL);
+ assert_return(ll->address != 0, -EINVAL);
+ assert_return(!ether_addr_is_nul(&ll->mac_addr), -EINVAL);
+ assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
+
+ ll->defend_window = 0;
+
+ r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr);
+ if (r < 0)
+ goto out;
+
+ ll->fd = safe_close(ll->fd);
+ ll->fd = r;
+
+ r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
+ EPOLLIN, ipv4acd_on_packet, ll);
+ if (r < 0)
+ goto out;
+
+ r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
+ if (r < 0)
+ goto out;
+
+ r = sd_event_source_set_description(ll->receive_message, "ipv4acd-receive-message");
+ if (r < 0)
+ goto out;
+
+ r = ipv4acd_set_next_wakeup(ll, 0, 0);
+ if (r < 0)
+ goto out;
+out:
+ if (r < 0) {
+ ipv4acd_stop(ll);
+ return r;
+ }
+
+ return 0;
+}
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index 14b9444dab..57bd337a9a 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -2,6 +2,7 @@
This file is part of systemd.
Copyright (C) 2014 Axis Communications AB. All rights reserved.
+ Copyright (C) 2015 Tom Gundersen
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -23,429 +24,154 @@
#include <stdio.h>
#include <arpa/inet.h>
-#include "util.h"
-#include "siphash24.h"
+#include "event-util.h"
+#include "in-addr-util.h"
#include "list.h"
#include "random-util.h"
+#include "refcnt.h"
+#include "siphash24.h"
+#include "sparse-endian.h"
+#include "util.h"
-#include "ipv4ll-internal.h"
+#include "sd-ipv4acd.h"
#include "sd-ipv4ll.h"
-/* Constants from the RFC */
-#define PROBE_WAIT 1
-#define PROBE_NUM 3
-#define PROBE_MIN 1
-#define PROBE_MAX 2
-#define ANNOUNCE_WAIT 2
-#define ANNOUNCE_NUM 2
-#define ANNOUNCE_INTERVAL 2
-#define MAX_CONFLICTS 10
-#define RATE_LIMIT_INTERVAL 60
-#define DEFEND_INTERVAL 10
-
#define IPV4LL_NETWORK 0xA9FE0000L
#define IPV4LL_NETMASK 0xFFFF0000L
-typedef enum IPv4LLTrigger{
- IPV4LL_TRIGGER_NULL,
- IPV4LL_TRIGGER_PACKET,
- IPV4LL_TRIGGER_TIMEOUT,
- _IPV4LL_TRIGGER_MAX,
- _IPV4LL_TRIGGER_INVALID = -1
-} IPv4LLTrigger;
-
-typedef enum IPv4LLState {
- IPV4LL_STATE_INIT,
- IPV4LL_STATE_WAITING_PROBE,
- IPV4LL_STATE_PROBING,
- IPV4LL_STATE_WAITING_ANNOUNCE,
- IPV4LL_STATE_ANNOUNCING,
- IPV4LL_STATE_RUNNING,
- IPV4LL_STATE_STOPPED,
- _IPV4LL_STATE_MAX,
- _IPV4LL_STATE_INVALID = -1
-} IPv4LLState;
+#define IPV4LL_DONT_DESTROY(ll) \
+ _cleanup_ipv4ll_unref_ _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll)
struct sd_ipv4ll {
unsigned n_ref;
- IPv4LLState state;
- int index;
- int fd;
- union sockaddr_union link;
- int iteration;
- int conflict;
- sd_event_source *receive_message;
- sd_event_source *timer;
- usec_t next_wakeup;
- usec_t defend_window;
- int next_wakeup_valid;
- be32_t address;
+ sd_ipv4acd *acd;
+ be32_t address; /* the address pushed to ACD */
struct random_data *random_data;
char *random_data_state;
+
/* External */
be32_t claimed_address;
- struct ether_addr mac_addr;
- sd_event *event;
- int event_priority;
sd_ipv4ll_cb_t cb;
void* userdata;
};
-static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data);
-
-static void ipv4ll_set_state(sd_ipv4ll *ll, IPv4LLState st, int reset_counter) {
-
- assert(ll);
- assert(st < _IPV4LL_STATE_MAX);
-
- if (st == ll->state && !reset_counter) {
- ll->iteration++;
- } else {
- ll->state = st;
- ll->iteration = 0;
- }
-}
-
-static sd_ipv4ll *ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
- assert(ll);
-
- if (ll->cb) {
- ll = sd_ipv4ll_ref(ll);
- ll->cb(ll, event, ll->userdata);
- ll = sd_ipv4ll_unref(ll);
- }
-
- return ll;
-}
-
-static sd_ipv4ll *ipv4ll_stop(sd_ipv4ll *ll, int event) {
- assert(ll);
-
- ll->receive_message = sd_event_source_unref(ll->receive_message);
- ll->fd = safe_close(ll->fd);
-
- ll->timer = sd_event_source_unref(ll->timer);
-
- log_ipv4ll(ll, "STOPPED");
-
- ll = ipv4ll_client_notify(ll, event);
+sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) {
+ if (!ll)
+ return NULL;
- if (ll) {
- ll->claimed_address = 0;
- ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
- }
+ assert(ll->n_ref >= 1);
+ ll->n_ref++;
return ll;
}
-static int ipv4ll_pick_address(sd_ipv4ll *ll, be32_t *address) {
- be32_t addr;
- int r;
- int32_t random;
-
- assert(ll);
- assert(address);
- assert(ll->random_data);
-
- do {
- r = random_r(ll->random_data, &random);
- if (r < 0)
- return r;
- addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
- } while (addr == ll->address ||
- (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
- (ntohl(addr) & 0x0000FF00) == 0x0000 ||
- (ntohl(addr) & 0x0000FF00) == 0xFF00);
-
- *address = addr;
- return 0;
-}
-
-static int ipv4ll_timer(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_ipv4ll *ll = (sd_ipv4ll*)userdata;
-
- assert(ll);
-
- ll->next_wakeup_valid = 0;
- ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_TIMEOUT, NULL);
-
- return 0;
-}
-
-static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) {
- usec_t next_timeout = 0;
- usec_t time_now = 0;
-
- assert(sec >= 0);
- assert(random_sec >= 0);
- assert(ll);
-
- next_timeout = sec * USEC_PER_SEC;
-
- if (random_sec)
- next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
-
- assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
-
- ll->next_wakeup = time_now + next_timeout;
- ll->next_wakeup_valid = 1;
-}
-
-static bool ipv4ll_arp_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
- assert(ll);
- assert(arp);
-
- if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0 &&
- memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN) != 0)
- return true;
+sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
+ if (!ll)
+ return NULL;
- return false;
-}
+ assert(ll->n_ref >= 1);
+ ll->n_ref--;
-static bool ipv4ll_arp_probe_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
- assert(ll);
- assert(arp);
+ if (ll->n_ref > 0)
+ return NULL;
- if (ipv4ll_arp_conflict(ll, arp))
- return true;
+ sd_ipv4acd_unref(ll->acd);
- if (memcmp(arp->arp_tpa, &ll->address, sizeof(ll->address)) == 0 &&
- memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN))
- return true;
+ free(ll->random_data);
+ free(ll->random_data_state);
+ free(ll);
- return false;
+ return NULL;
}
-static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data) {
- struct ether_arp out_packet;
- int out_packet_ready = 0;
- int r = 0;
-
- assert(ll);
- assert(trigger < _IPV4LL_TRIGGER_MAX);
-
- if (ll->state == IPV4LL_STATE_INIT) {
-
- log_ipv4ll(ll, "PROBE");
- ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
- ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
-
- } else if ((ll->state == IPV4LL_STATE_WAITING_PROBE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
- (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < PROBE_NUM-2)) {
-
- /* Send a probe */
- arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
- out_packet_ready = 1;
- ipv4ll_set_state(ll, IPV4LL_STATE_PROBING, 0);
-
- ipv4ll_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
-
- } else if (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration >= PROBE_NUM-2) {
-
- /* Send the last probe */
- arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
- out_packet_ready = 1;
- ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_ANNOUNCE, 1);
-
- ipv4ll_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
-
- } else if ((ll->state == IPV4LL_STATE_WAITING_ANNOUNCE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
- (ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < ANNOUNCE_NUM-1)) {
-
- /* Send announcement packet */
- arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
- out_packet_ready = 1;
- ipv4ll_set_state(ll, IPV4LL_STATE_ANNOUNCING, 0);
-
- ipv4ll_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
-
- if (ll->iteration == 0) {
- log_ipv4ll(ll, "ANNOUNCE");
- ll->claimed_address = ll->address;
- ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND);
- if (!ll || ll->state == IPV4LL_STATE_STOPPED)
- goto out;
-
- ll->conflict = 0;
- }
-
- } else if ((ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT &&
- ll->iteration >= ANNOUNCE_NUM-1)) {
-
- ipv4ll_set_state(ll, IPV4LL_STATE_RUNNING, 0);
- ll->next_wakeup_valid = 0;
-
- } else if (trigger == IPV4LL_TRIGGER_PACKET) {
-
- int conflicted = 0;
- usec_t time_now;
- struct ether_arp* in_packet = (struct ether_arp*)trigger_data;
-
- assert(in_packet);
-
- if (IN_SET(ll->state, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING)) {
-
- if (ipv4ll_arp_conflict(ll, in_packet)) {
-
- r = sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now);
- if (r < 0)
- goto out;
-
- /* Defend address */
- if (time_now > ll->defend_window) {
- ll->defend_window = time_now + DEFEND_INTERVAL * USEC_PER_SEC;
- arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
- out_packet_ready = 1;
- } else
- conflicted = 1;
- }
-
- } else if (IN_SET(ll->state, IPV4LL_STATE_WAITING_PROBE,
- IPV4LL_STATE_PROBING,
- IPV4LL_STATE_WAITING_ANNOUNCE)) {
-
- conflicted = ipv4ll_arp_probe_conflict(ll, in_packet);
- }
-
- if (conflicted) {
- log_ipv4ll(ll, "CONFLICT");
- ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
- if (!ll || ll->state == IPV4LL_STATE_STOPPED)
- goto out;
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref);
+#define _cleanup_ipv4ll_unref_ _cleanup_(sd_ipv4ll_unrefp)
- ll->claimed_address = 0;
+static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata);
- /* Pick a new address */
- r = ipv4ll_pick_address(ll, &ll->address);
- if (r < 0)
- goto out;
- ll->conflict++;
- ll->defend_window = 0;
- ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
+int sd_ipv4ll_new(sd_ipv4ll **ret) {
+ _cleanup_ipv4ll_unref_ sd_ipv4ll *ll = NULL;
+ int r;
- if (ll->conflict >= MAX_CONFLICTS) {
- log_ipv4ll(ll, "MAX_CONFLICTS");
- ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
- } else
- ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
+ assert_return(ret, -EINVAL);
- }
- }
+ ll = new0(sd_ipv4ll, 1);
+ if (!ll)
+ return -ENOMEM;
- if (out_packet_ready) {
- r = arp_network_send_raw_socket(ll->fd, &ll->link, &out_packet);
- if (r < 0) {
- log_ipv4ll(ll, "failed to send arp packet out");
- goto out;
- }
- }
+ r = sd_ipv4acd_new(&ll->acd);
+ if (r < 0)
+ return r;
- if (ll->next_wakeup_valid) {
- ll->timer = sd_event_source_unref(ll->timer);
- r = sd_event_add_time(ll->event, &ll->timer, clock_boottime_or_monotonic(),
- ll->next_wakeup, 0, ipv4ll_timer, ll);
- if (r < 0)
- goto out;
+ r = sd_ipv4acd_set_callback(ll->acd, ipv4ll_on_acd, ll);
+ if (r < 0)
+ return r;
- r = sd_event_source_set_priority(ll->timer, ll->event_priority);
- if (r < 0)
- goto out;
+ ll->n_ref = 1;
- r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
- if (r < 0)
- goto out;
- }
+ *ret = ll;
+ ll = NULL;
-out:
- if (r < 0 && ll)
- ipv4ll_stop(ll, r);
+ return 0;
}
-static int ipv4ll_receive_message(sd_event_source *s, int fd,
- uint32_t revents, void *userdata) {
+int sd_ipv4ll_stop(sd_ipv4ll *ll) {
int r;
- struct ether_arp arp;
- sd_ipv4ll *ll = (sd_ipv4ll*)userdata;
-
- assert(ll);
- r = read(fd, &arp, sizeof(struct ether_arp));
- if (r < (int) sizeof(struct ether_arp))
- return 0;
+ assert_return(ll, -EINVAL);
- r = arp_packet_verify_headers(&arp);
+ r = sd_ipv4acd_stop(ll->acd);
if (r < 0)
- return 0;
-
- ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_PACKET, &arp);
+ return r;
return 0;
}
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) {
assert_return(ll, -EINVAL);
- assert_return(interface_index > 0, -EINVAL);
- assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT,
- IPV4LL_STATE_STOPPED), -EBUSY);
- ll->index = interface_index;
-
- return 0;
+ return sd_ipv4acd_set_index(ll->acd, interface_index);
}
+#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
+
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
- bool need_restart = false;
+ int r;
assert_return(ll, -EINVAL);
- assert_return(addr, -EINVAL);
-
- if (memcmp(&ll->mac_addr, addr, ETH_ALEN) == 0)
- return 0;
- if (!IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED)) {
- log_ipv4ll(ll, "Changing MAC address on running IPv4LL "
- "client, restarting");
- ll = ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
- need_restart = true;
- }
+ if (!ll->random_data) {
+ uint8_t seed[8];
- if (!ll)
- return 0;
+ /* If no random data is set, generate some from the MAC */
+ siphash24(seed, &addr->ether_addr_octet,
+ ETH_ALEN, HASH_KEY.bytes);
- memcpy(&ll->mac_addr, addr, ETH_ALEN);
+ assert_cc(sizeof(unsigned) <= 8);
- if (need_restart)
- sd_ipv4ll_start(ll);
+ r = sd_ipv4ll_set_address_seed(ll, *(unsigned*)seed);
+ if (r < 0)
+ return r;
+ }
- return 0;
+ return sd_ipv4acd_set_mac(ll->acd, addr);
}
int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
assert_return(ll, -EINVAL);
- ll->event = sd_event_unref(ll->event);
-
- return 0;
+ return sd_ipv4acd_detach_event(ll->acd);
}
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
int r;
assert_return(ll, -EINVAL);
- assert_return(!ll->event, -EBUSY);
-
- if (event)
- ll->event = sd_event_ref(event);
- else {
- r = sd_event_default(&ll->event);
- if (r < 0) {
- ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
- return r;
- }
- }
- ll->event_priority = priority;
+ r = sd_ipv4acd_attach_event(ll->acd, event, priority);
+ if (r < 0)
+ return r;
return 0;
}
@@ -467,189 +193,176 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){
return -ENOENT;
address->s_addr = ll->claimed_address;
+
return 0;
}
-int sd_ipv4ll_set_address_seed (sd_ipv4ll *ll, uint8_t seed[8]) {
- unsigned int entropy;
+int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
+ _cleanup_free_ struct random_data *random_data = NULL;
+ _cleanup_free_ char *random_data_state = NULL;
int r;
assert_return(ll, -EINVAL);
- assert_return(seed, -EINVAL);
- entropy = *seed;
+ random_data = new0(struct random_data, 1);
+ if (!random_data)
+ return -ENOMEM;
- free(ll->random_data);
- free(ll->random_data_state);
+ random_data_state = new0(char, 128);
+ if (!random_data_state)
+ return -ENOMEM;
- ll->random_data = new0(struct random_data, 1);
- ll->random_data_state = new0(char, 128);
+ r = initstate_r(seed, random_data_state, 128, random_data);
+ if (r < 0)
+ return r;
- if (!ll->random_data || !ll->random_data_state) {
- r = -ENOMEM;
- goto error;
- }
+ free(ll->random_data);
+ ll->random_data = random_data;
+ random_data = NULL;
- r = initstate_r((unsigned int)entropy, ll->random_data_state, 128, ll->random_data);
- if (r < 0)
- goto error;
+ free(ll->random_data_state);
+ ll->random_data_state = random_data_state;
+ random_data_state = NULL;
-error:
- if (r < 0){
- free(ll->random_data);
- free(ll->random_data_state);
- ll->random_data = NULL;
- ll->random_data_state = NULL;
- }
- return r;
+ return 0;
}
bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
assert_return(ll, false);
- return !IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED);
+ return sd_ipv4acd_is_running(ll->acd);
}
-#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
-
-int sd_ipv4ll_start (sd_ipv4ll *ll) {
- int r;
+static bool ipv4ll_address_is_valid(const struct in_addr *address) {
+ uint32_t addr;
- assert_return(ll, -EINVAL);
- assert_return(ll->event, -EINVAL);
- assert_return(ll->index > 0, -EINVAL);
- assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT,
- IPV4LL_STATE_STOPPED), -EBUSY);
-
- ll->state = IPV4LL_STATE_INIT;
-
- r = arp_network_bind_raw_socket(ll->index, &ll->link);
-
- if (r < 0)
- goto out;
+ assert(address);
- ll->fd = r;
- ll->conflict = 0;
- ll->defend_window = 0;
- ll->claimed_address = 0;
+ if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address))
+ return false;
- if (!ll->random_data) {
- uint8_t seed[8];
+ addr = be32toh(address->s_addr);
- /* Fallback to mac */
- siphash24(seed, &ll->mac_addr.ether_addr_octet,
- ETH_ALEN, HASH_KEY.bytes);
+ if ((addr & 0x0000FF00) == 0x0000 ||
+ (addr & 0x0000FF00) == 0xFF00)
+ return false;
- r = sd_ipv4ll_set_address_seed(ll, seed);
- if (r < 0)
- goto out;
- }
+ return true;
+}
- if (ll->address == 0) {
- r = ipv4ll_pick_address(ll, &ll->address);
- if (r < 0)
- goto out;
- }
+int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) {
+ int r;
- ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
+ assert_return(ll, -EINVAL);
+ assert_return(address, -EINVAL);
+ assert_return(ipv4ll_address_is_valid(address), -EINVAL);
- r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
- EPOLLIN, ipv4ll_receive_message, ll);
+ r = sd_ipv4acd_set_address(ll->acd, address);
if (r < 0)
- goto out;
+ return r;
- r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
- if (r < 0)
- goto out;
+ ll->address = address->s_addr;
- r = sd_event_source_set_description(ll->receive_message, "ipv4ll-receive-message");
- if (r < 0)
- goto out;
+ return 0;
+}
+
+static int ipv4ll_pick_address(sd_ipv4ll *ll) {
+ struct in_addr in_addr;
+ be32_t addr;
+ int r;
+ int32_t random;
- r = sd_event_add_time(ll->event,
- &ll->timer,
- clock_boottime_or_monotonic(),
- now(clock_boottime_or_monotonic()), 0,
- ipv4ll_timer, ll);
+ assert(ll);
+ assert(ll->random_data);
- if (r < 0)
- goto out;
+ do {
+ r = random_r(ll->random_data, &random);
+ if (r < 0)
+ return r;
+ addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
+ } while (addr == ll->address ||
+ (ntohl(addr) & 0x0000FF00) == 0x0000 ||
+ (ntohl(addr) & 0x0000FF00) == 0xFF00);
- r = sd_event_source_set_priority(ll->timer, ll->event_priority);
- if (r < 0)
- goto out;
+ in_addr.s_addr = addr;
- r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
-out:
+ r = sd_ipv4ll_set_address(ll, &in_addr);
if (r < 0)
- ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
+ return r;
return 0;
}
-int sd_ipv4ll_stop(sd_ipv4ll *ll) {
- ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
- if (ll)
- ipv4ll_set_state(ll, IPV4LL_STATE_STOPPED, 1);
-
- return 0;
-}
+int sd_ipv4ll_start(sd_ipv4ll *ll) {
+ int r;
-sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) {
+ assert_return(ll, -EINVAL);
+ assert_return(ll->random_data, -EINVAL);
- if (!ll)
- return NULL;
+ if (ll->address == 0) {
+ r = ipv4ll_pick_address(ll);
+ if (r < 0)
+ return r;
+ }
- assert(ll->n_ref >= 1);
- ll->n_ref++;
+ r = sd_ipv4acd_start(ll->acd);
+ if (r < 0)
+ return r;
- return ll;
+ return 0;
}
-sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
-
- if (!ll)
- return NULL;
-
- assert(ll->n_ref >= 1);
- ll->n_ref--;
+static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
+ assert(ll);
- if (ll->n_ref > 0)
- return ll;
+ if (ll->cb)
+ ll->cb(ll, event, ll->userdata);
+}
- ll->receive_message = sd_event_source_unref(ll->receive_message);
- ll->fd = safe_close(ll->fd);
+void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
+ sd_ipv4ll *ll = userdata;
+ IPV4LL_DONT_DESTROY(ll);
+ int r;
- ll->timer = sd_event_source_unref(ll->timer);
+ assert(acd);
+ assert(ll);
- sd_ipv4ll_detach_event(ll);
+ switch (event) {
+ case SD_IPV4ACD_EVENT_STOP:
+ ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
- free(ll->random_data);
- free(ll->random_data_state);
- free(ll);
+ ll->claimed_address = 0;
- return NULL;
-}
+ break;
+ case SD_IPV4ACD_EVENT_BIND:
+ ll->claimed_address = ll->address;
+ ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_BIND);
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref);
-#define _cleanup_ipv4ll_free_ _cleanup_(sd_ipv4ll_unrefp)
+ break;
+ case SD_IPV4ACD_EVENT_CONFLICT:
+ /* if an address was already bound we must call up to the
+ user to handle this, otherwise we just try again */
+ if (ll->claimed_address != 0) {
+ ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_CONFLICT);
-int sd_ipv4ll_new(sd_ipv4ll **ret) {
- _cleanup_ipv4ll_free_ sd_ipv4ll *ll = NULL;
-
- assert_return(ret, -EINVAL);
+ ll->claimed_address = 0;
+ } else {
+ r = ipv4ll_pick_address(ll);
+ if (r < 0)
+ goto error;
- ll = new0(sd_ipv4ll, 1);
- if (!ll)
- return -ENOMEM;
+ r = sd_ipv4acd_start(ll->acd);
+ if (r < 0)
+ goto error;
+ }
- ll->n_ref = 1;
- ll->state = IPV4LL_STATE_INIT;
- ll->index = -1;
- ll->fd = -1;
+ break;
+ default:
+ assert_not_reached("Invalid IPv4ACD event.");
+ }
- *ret = ll;
- ll = NULL;
+ return;
- return 0;
+error:
+ ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP);
}
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index 574e04b541..06949a1e83 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -68,16 +68,14 @@ struct sd_lldp {
lldp_agent_statistics statistics;
};
-static unsigned long chassis_id_hash_func(const void *p,
- const uint8_t hash_key[HASH_KEY_SIZE]) {
- uint64_t u;
+static void chassis_id_hash_func(const void *p, struct siphash *state) {
const lldp_chassis_id *id = p;
assert(id);
+ assert(id->data);
- siphash24((uint8_t *) &u, id->data, id->length, hash_key);
-
- return (unsigned long) u;
+ siphash24_compress(&id->length, sizeof(id->length), state);
+ siphash24_compress(id->data, id->length, state);
}
static int chassis_id_compare_func(const void *_a, const void *_b) {
@@ -199,7 +197,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) {
goto out;
}
- /* skip type and lengh encoding */
+ /* skip type and length encoding */
p += 2;
q = p;
@@ -338,7 +336,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) {
lldp->statistics.stats_frames_in_errors_total ++;
}
- tlv_packet_free(tlv);
+ sd_lldp_packet_unref(tlv);
return 0;
}
@@ -366,10 +364,16 @@ static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state) {
}
static void lldp_run_state_machine(sd_lldp *lldp) {
+ if (!lldp->cb)
+ return;
- if (lldp->rx_state == LLDP_AGENT_RX_UPDATE_INFO)
- if (lldp->cb)
- lldp->cb(lldp, LLDP_AGENT_RX_UPDATE_INFO, lldp->userdata);
+ switch (lldp->rx_state) {
+ case LLDP_AGENT_RX_UPDATE_INFO:
+ lldp->cb(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata);
+ break;
+ default:
+ break;
+ }
}
/* 10.5.5.2.1 mibDeleteObjects ()
@@ -449,7 +453,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
_cleanup_free_ char *s = NULL;
char *k, *t;
- r = lldp_read_chassis_id(p->packet, &type, &length, &mac);
+ r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length);
if (r < 0)
continue;
@@ -462,7 +466,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
goto fail;
}
- r = lldp_read_port_id(p->packet, &type, &length, &port_id);
+ r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length);
if (r < 0)
continue;
@@ -507,7 +511,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
free(s);
s = k;
- r = lldp_read_system_name(p->packet, &length, &k);
+ r = sd_lldp_packet_read_system_name(p->packet, &k, &length);
if (r < 0)
k = strappend(s, "'_NAME=N/A' ");
else {
@@ -529,7 +533,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
free(s);
s = k;
- (void) lldp_read_system_capability(p->packet, &data);
+ (void) sd_lldp_packet_read_system_capability(p->packet, &data);
sprintf(buf, "'_CAP=%x'", data);
@@ -696,3 +700,35 @@ int sd_lldp_new(int ifindex,
return 0;
}
+
+int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs) {
+ lldp_neighbour_port *p;
+ lldp_chassis *c;
+ Iterator iter;
+ unsigned count = 0, i;
+
+ assert_return(lldp, -EINVAL);
+ assert_return(tlvs, -EINVAL);
+
+ HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) {
+ LIST_FOREACH(port, p, c->ports)
+ count++;
+ }
+
+ if (!count) {
+ *tlvs = NULL;
+ return 0;
+ }
+
+ *tlvs = new(sd_lldp_packet *, count);
+ if (!*tlvs)
+ return -ENOMEM;
+
+ i = 0;
+ HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) {
+ LIST_FOREACH(port, p, c->ports)
+ (*tlvs)[i++] = sd_lldp_packet_ref(p->packet);
+ }
+
+ return count;
+}
diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c
index c6c9da812b..cd5a204f8c 100644
--- a/src/libsystemd-network/sd-pppoe.c
+++ b/src/libsystemd-network/sd-pppoe.c
@@ -385,7 +385,7 @@ static int pppoe_send_initiation(sd_pppoe *ppp) {
return r;
log_debug("PPPoE: sent DISCOVER (Service-Name: %s)",
- ppp->service_name ? : "");
+ strna(ppp->service_name));
pppoe_arm_timeout(ppp);
@@ -625,8 +625,8 @@ static int pppoe_handle_message(sd_pppoe *ppp, struct pppoe_hdr *packet, struct
mac->ether_addr_octet[3],
mac->ether_addr_octet[4],
mac->ether_addr_octet[5],
- ppp->tags.service_name ? : "",
- ppp->tags.ac_name ? : "");
+ strempty(ppp->tags.service_name),
+ strempty(ppp->tags.ac_name));
memcpy(&ppp->peer_mac, mac, ETH_ALEN);
@@ -670,7 +670,7 @@ static int pppoe_handle_message(sd_pppoe *ppp, struct pppoe_hdr *packet, struct
ppp->timeout = sd_event_source_unref(ppp->timeout);
assert(ppp->cb);
- ppp->cb(ppp, PPPOE_EVENT_RUNNING, ppp->userdata);
+ ppp->cb(ppp, SD_PPPOE_EVENT_RUNNING, ppp->userdata);
break;
case PPPOE_STATE_RUNNING:
@@ -688,7 +688,7 @@ static int pppoe_handle_message(sd_pppoe *ppp, struct pppoe_hdr *packet, struct
ppp->state = PPPOE_STATE_STOPPED;
assert(ppp->cb);
- ppp->cb(ppp, PPPOE_EVENT_STOPPED, ppp->userdata);
+ ppp->cb(ppp, SD_PPPOE_EVENT_STOPPED, ppp->userdata);
break;
case PPPOE_STATE_STOPPED:
diff --git a/src/libsystemd-network/test-acd.c b/src/libsystemd-network/test-acd.c
new file mode 100644
index 0000000000..94c31af3f3
--- /dev/null
+++ b/src/libsystemd-network/test-acd.c
@@ -0,0 +1,117 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <linux/veth.h>
+#include <net/if.h>
+
+#include "sd-event.h"
+#include "sd-netlink.h"
+#include "sd-ipv4acd.h"
+
+#include "util.h"
+#include "event-util.h"
+#include "netlink-util.h"
+#include "in-addr-util.h"
+
+static void acd_handler(sd_ipv4acd *acd, int event, void *userdata) {
+ assert_se(acd);
+
+ switch (event) {
+ case SD_IPV4ACD_EVENT_BIND:
+ log_info("bound");
+ break;
+ case SD_IPV4ACD_EVENT_CONFLICT:
+ log_info("conflict");
+ break;
+ case SD_IPV4ACD_EVENT_STOP:
+ log_error("the client was stopped");
+ break;
+ default:
+ assert_not_reached("invalid ACD event");
+ }
+}
+
+static int client_run(int ifindex, const struct in_addr *pa, const struct ether_addr *ha, sd_event *e) {
+ sd_ipv4acd *acd;
+
+ assert_se(sd_ipv4acd_new(&acd) >= 0);
+ assert_se(sd_ipv4acd_attach_event(acd, e, 0) >= 0);
+
+ assert_se(sd_ipv4acd_set_index(acd, ifindex) >= 0);
+ assert_se(sd_ipv4acd_set_mac(acd, ha) >= 0);
+ assert_se(sd_ipv4acd_set_address(acd, pa) >= 0);
+ assert_se(sd_ipv4acd_set_callback(acd, acd_handler, NULL) >= 0);
+
+ log_info("starting IPv4ACD client");
+
+ assert_se(sd_ipv4acd_start(acd) >= 0);
+
+ assert_se(sd_event_loop(e) >= 0);
+
+ assert_se(!sd_ipv4acd_unref(acd));
+
+ return EXIT_SUCCESS;
+}
+
+static int test_acd(const char *ifname, const char *address) {
+ _cleanup_event_unref_ sd_event *e = NULL;
+ _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *reply = NULL;
+ union in_addr_union pa;
+ struct ether_addr ha;
+ int ifindex;
+
+ assert_se(in_addr_from_string(AF_INET, address, &pa) >= 0);
+
+ assert_se(sd_event_new(&e) >= 0);
+
+ assert_se(sd_netlink_open(&rtnl) >= 0);
+ assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
+
+ assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, 0) >= 0);
+ assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, ifname) >= 0);
+ assert_se(sd_netlink_call(rtnl, m, 0, &reply) >= 0);
+
+ assert_se(sd_rtnl_message_link_get_ifindex(reply, &ifindex) >= 0);
+ assert_se(sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &ha) >= 0);
+
+ client_run(ifindex, &pa.in, &ha, e);
+
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char *argv[]) {
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
+ if (argc == 3)
+ return test_acd(argv[1], argv[2]);
+ else {
+ log_error("This program takes two arguments.\n"
+ "\t %s <ifname> <IPv4 address>", program_invocation_short_name);
+ return EXIT_FAILURE;
+ }
+}
diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c
index 29c20b77e3..c112ec8134 100644
--- a/src/libsystemd-network/test-dhcp-client.c
+++ b/src/libsystemd-network/test-dhcp-client.c
@@ -360,7 +360,7 @@ static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
struct in_addr addr;
assert_se(client);
- assert_se(event == DHCP_EVENT_IP_ACQUIRE);
+ assert_se(event == SD_DHCP_CLIENT_EVENT_IP_ACQUIRE);
assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
assert_se(lease);
diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c
index 7d8a1f6bd9..c3bcb9cb4b 100644
--- a/src/libsystemd-network/test-dhcp-server.c
+++ b/src/libsystemd-network/test-dhcp-server.c
@@ -198,6 +198,17 @@ static void test_message_handler(void) {
assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0);
}
+static uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZE]) {
+ struct siphash state;
+ uint64_t hash;
+
+ siphash24_init(&state, key);
+ client_id_hash_func(id, &state);
+ siphash24_finalize((uint8_t*)&hash, &state);
+
+ return hash;
+}
+
static void test_client_id_hash(void) {
DHCPClientId a = {
.length = 4,
@@ -213,18 +224,18 @@ static void test_client_id_hash(void) {
b.data = (uint8_t*)strdup("abcd");
assert_se(client_id_compare_func(&a, &b) == 0);
- assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
+ assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
a.length = 3;
assert_se(client_id_compare_func(&a, &b) != 0);
a.length = 4;
assert_se(client_id_compare_func(&a, &b) == 0);
- assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
+ assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
b.length = 3;
assert_se(client_id_compare_func(&a, &b) != 0);
b.length = 4;
assert_se(client_id_compare_func(&a, &b) == 0);
- assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key));
+ assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key));
free(b.data);
b.data = (uint8_t*)strdup("abce");
diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c
index 9c7f9ffb1b..0c131a9897 100644
--- a/src/libsystemd-network/test-dhcp6-client.c
+++ b/src/libsystemd-network/test-dhcp6-client.c
@@ -365,7 +365,7 @@ static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
char **domains;
assert_se(e);
- assert_se(event == DHCP6_EVENT_IP_ACQUIRE);
+ assert_se(event == SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE);
assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0);
@@ -564,7 +564,7 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event,
char **domains;
assert_se(e);
- assert_se(event == DHCP6_EVENT_INFORMATION_REQUEST);
+ assert_se(event == SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST);
assert_se(sd_dhcp6_client_get_lease(client, &lease) >= 0);
@@ -581,7 +581,11 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event,
if (verbose)
printf(" got DHCPv6 event %d\n", event);
+ assert_se(sd_dhcp6_client_set_information_request(client, false) == -EBUSY);
+ assert_se(sd_dhcp6_client_set_callback(client, NULL, e) >= 0);
+ assert_se(sd_dhcp6_client_stop(client) >= 0);
assert_se(sd_dhcp6_client_set_information_request(client, false) >= 0);
+
assert_se(sd_dhcp6_client_set_callback(client,
test_client_solicit_cb, e) >= 0);
diff --git a/src/libsystemd-network/test-icmp6-rs.c b/src/libsystemd-network/test-icmp6-rs.c
index 8ba21106a7..27b0ef4572 100644
--- a/src/libsystemd-network/test-icmp6-rs.c
+++ b/src/libsystemd-network/test-icmp6-rs.c
@@ -277,9 +277,9 @@ static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) {
uint8_t flag;
int event;
} flag_event[] = {
- { 0, ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE },
- { ND_RA_FLAG_OTHER, ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER },
- { ND_RA_FLAG_MANAGED, ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED }
+ { 0, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE },
+ { ND_RA_FLAG_OTHER, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER },
+ { ND_RA_FLAG_MANAGED, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED }
};
uint32_t mtu;
diff --git a/src/libsystemd-network/test-ipv4ll-manual.c b/src/libsystemd-network/test-ipv4ll-manual.c
new file mode 100644
index 0000000000..dd2e44e7a3
--- /dev/null
+++ b/src/libsystemd-network/test-ipv4ll-manual.c
@@ -0,0 +1,129 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <linux/veth.h>
+#include <net/if.h>
+
+#include "sd-event.h"
+#include "sd-netlink.h"
+#include "sd-ipv4ll.h"
+
+#include "util.h"
+#include "event-util.h"
+#include "netlink-util.h"
+#include "in-addr-util.h"
+
+static void ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
+ _cleanup_free_ char *address = NULL;
+ struct in_addr addr = {};
+
+ assert_se(ll);
+
+ if (sd_ipv4ll_get_address(ll, &addr) >= 0)
+ assert_se(in_addr_to_string(AF_INET, (const union in_addr_union*) &addr, &address) >= 0);
+
+ switch (event) {
+ case SD_IPV4LL_EVENT_BIND:
+ log_info("bound %s", strna(address));
+ break;
+ case SD_IPV4LL_EVENT_CONFLICT:
+ log_info("conflict on %s", strna(address));
+ break;
+ case SD_IPV4LL_EVENT_STOP:
+ log_error("the client was stopped with address %s", strna(address));
+ break;
+ default:
+ assert_not_reached("invalid LL event");
+ }
+}
+
+static int client_run(int ifindex, const char *seed_str, const struct ether_addr *ha, sd_event *e) {
+ sd_ipv4ll *ll;
+
+ assert_se(sd_ipv4ll_new(&ll) >= 0);
+ assert_se(sd_ipv4ll_attach_event(ll, e, 0) >= 0);
+
+ assert_se(sd_ipv4ll_set_index(ll, ifindex) >= 0);
+ assert_se(sd_ipv4ll_set_mac(ll, ha) >= 0);
+ assert_se(sd_ipv4ll_set_callback(ll, ll_handler, NULL) >= 0);
+
+ if (seed_str) {
+ unsigned seed;
+
+ assert_se(safe_atou(seed_str, &seed) >= 0);
+
+ assert_se(sd_ipv4ll_set_address_seed(ll, seed) >= 0);
+ }
+
+ log_info("starting IPv4LL client");
+
+ assert_se(sd_ipv4ll_start(ll) >= 0);
+
+ assert_se(sd_event_loop(e) >= 0);
+
+ assert_se(!sd_ipv4ll_unref(ll));
+
+ return EXIT_SUCCESS;
+}
+
+static int test_ll(const char *ifname, const char *seed) {
+ _cleanup_event_unref_ sd_event *e = NULL;
+ _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *reply = NULL;
+ struct ether_addr ha;
+ int ifindex;
+
+ assert_se(sd_event_new(&e) >= 0);
+
+ assert_se(sd_netlink_open(&rtnl) >= 0);
+ assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
+
+ assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, 0) >= 0);
+ assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, ifname) >= 0);
+ assert_se(sd_netlink_call(rtnl, m, 0, &reply) >= 0);
+
+ assert_se(sd_rtnl_message_link_get_ifindex(reply, &ifindex) >= 0);
+ assert_se(sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &ha) >= 0);
+
+ client_run(ifindex, seed, &ha, e);
+
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char *argv[]) {
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
+ if (argc == 2)
+ return test_ll(argv[1], NULL);
+ else if (argc == 3)
+ return test_ll(argv[1], argv[2]);
+ else {
+ log_error("This program takes one or two arguments.\n"
+ "\t %s <ifname> [<seed>]", program_invocation_short_name);
+ return EXIT_FAILURE;
+ }
+}
diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c
index d60ee98b25..b67a9f17d7 100644
--- a/src/libsystemd-network/test-ipv4ll.c
+++ b/src/libsystemd-network/test-ipv4ll.c
@@ -31,7 +31,7 @@
#include "event-util.h"
#include "sd-ipv4ll.h"
-#include "ipv4ll-internal.h"
+#include "arp-util.h"
static bool verbose = false;
static bool extended = false;
@@ -44,10 +44,10 @@ static void basic_request_handler(sd_ipv4ll *ll, int event, void *userdata) {
assert_se(userdata == basic_request_handler_userdata);
switch(event) {
- case IPV4LL_EVENT_STOP:
+ case SD_IPV4LL_EVENT_STOP:
basic_request_handler_stop = 1;
break;
- case IPV4LL_EVENT_BIND:
+ case SD_IPV4LL_EVENT_BIND:
basic_request_handler_bind = 1;
break;
default:
@@ -56,10 +56,10 @@ static void basic_request_handler(sd_ipv4ll *ll, int event, void *userdata) {
}
}
-int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
- const struct ether_arp *arp) {
+static int arp_network_send_raw_socket(int fd, int ifindex,
+ const struct ether_arp *arp) {
assert_se(arp);
- assert_se(link);
+ assert_se(ifindex > 0);
assert_se(fd >= 0);
if (send(fd, arp, sizeof(struct ether_arp), 0) < 0)
@@ -68,55 +68,40 @@ int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
return 0;
}
-int arp_network_bind_raw_socket(int index, union sockaddr_union *link) {
- if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
- return -errno;
+int arp_send_probe(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha) {
+ struct ether_arp ea = {};
- return test_fd[0];
-}
+ assert(fd >= 0);
+ assert(ifindex > 0);
+ assert(pa != 0);
+ assert(ha);
-static void test_arp_header(struct ether_arp *arp) {
- assert_se(arp);
- assert_se(arp->ea_hdr.ar_hrd == htons(ARPHRD_ETHER)); /* HTYPE */
- assert_se(arp->ea_hdr.ar_pro == htons(ETHERTYPE_IP)); /* PTYPE */
- assert_se(arp->ea_hdr.ar_hln == ETH_ALEN); /* HLEN */
- assert_se(arp->ea_hdr.ar_pln == sizeof arp->arp_spa); /* PLEN */
- assert_se(arp->ea_hdr.ar_op == htons(ARPOP_REQUEST)); /* REQUEST */
+ return arp_network_send_raw_socket(fd, ifindex, &ea);
}
-static void test_arp_probe(void) {
- struct ether_arp arp;
- struct ether_addr mac_addr = {
- .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}};
- be32_t pa = 0x3030;
+int arp_send_announcement(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha) {
+ struct ether_arp ea = {};
- if (verbose)
- printf("* %s\n", __FUNCTION__);
+ assert(fd >= 0);
+ assert(ifindex > 0);
+ assert(pa != 0);
+ assert(ha);
- arp_packet_probe(&arp, pa, &mac_addr);
- test_arp_header(&arp);
- assert_se(memcmp(arp.arp_sha, &mac_addr, ETH_ALEN) == 0);
- assert_se(memcmp(arp.arp_tpa, &pa, sizeof(pa)) == 0);
+ return arp_network_send_raw_socket(fd, ifindex, &ea);
}
-static void test_arp_announce(void) {
- struct ether_arp arp;
- struct ether_addr mac_addr = {
- .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}};
- be32_t pa = 0x3131;
-
- if (verbose)
- printf("* %s\n", __FUNCTION__);
+int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac) {
+ if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
+ return -errno;
- arp_packet_announcement(&arp, pa, &mac_addr);
- test_arp_header(&arp);
- assert_se(memcmp(arp.arp_sha, &mac_addr, ETH_ALEN) == 0);
- assert_se(memcmp(arp.arp_tpa, &pa, sizeof(pa)) == 0);
- assert_se(memcmp(arp.arp_spa, &pa, sizeof(pa)) == 0);
+ return test_fd[0];
}
static void test_public_api_setters(sd_event *e) {
- uint8_t seed[8];
+ struct in_addr address = {};
+ unsigned seed = 0;
sd_ipv4ll *ll;
struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}};
@@ -134,8 +119,17 @@ static void test_public_api_setters(sd_event *e) {
assert_se(sd_ipv4ll_set_callback(NULL, NULL, NULL) == -EINVAL);
assert_se(sd_ipv4ll_set_callback(ll, NULL, NULL) == 0);
- assert_se(sd_ipv4ll_set_address_seed(NULL, NULL) == -EINVAL);
- assert_se(sd_ipv4ll_set_address_seed(ll, NULL) == -EINVAL);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+ address.s_addr |= htobe32(169U << 24 | 254U << 16);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+ address.s_addr |= htobe32(0x00FF);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+ address.s_addr |= htobe32(0xF000);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == 0);
+ address.s_addr |= htobe32(0x0F00);
+ assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL);
+
+ assert_se(sd_ipv4ll_set_address_seed(NULL, seed) == -EINVAL);
assert_se(sd_ipv4ll_set_address_seed(ll, seed) == 0);
assert_se(sd_ipv4ll_set_mac(NULL, NULL) == -EINVAL);
@@ -149,7 +143,7 @@ static void test_public_api_setters(sd_event *e) {
assert_se(sd_ipv4ll_set_index(ll, 99) == 0);
assert_se(sd_ipv4ll_ref(ll) == ll);
- assert_se(sd_ipv4ll_unref(ll) == ll);
+ assert_se(sd_ipv4ll_unref(ll) == NULL);
/* Cleanup */
assert_se(sd_ipv4ll_unref(ll) == NULL);
@@ -184,21 +178,20 @@ static void test_basic_request(sd_event *e) {
sd_event_run(e, (uint64_t) -1);
assert_se(sd_ipv4ll_start(ll) == -EBUSY);
+ assert_se(sd_ipv4ll_is_running(ll));
+
/* PROBE */
sd_event_run(e, (uint64_t) -1);
assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp));
- test_arp_header(&arp);
if (extended) {
/* PROBE */
sd_event_run(e, (uint64_t) -1);
assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp));
- test_arp_header(&arp);
/* PROBE */
sd_event_run(e, (uint64_t) -1);
assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp));
- test_arp_header(&arp);
sd_event_run(e, (uint64_t) -1);
assert_se(basic_request_handler_bind == 1);
@@ -215,11 +208,13 @@ static void test_basic_request(sd_event *e) {
int main(int argc, char *argv[]) {
_cleanup_event_unref_ sd_event *e = NULL;
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
assert_se(sd_event_new(&e) >= 0);
test_public_api_setters(e);
- test_arp_probe();
- test_arp_announce();
test_basic_request(e);
return 0;
diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c
index 06545aee59..e57102a576 100644
--- a/src/libsystemd-network/test-lldp.c
+++ b/src/libsystemd-network/test-lldp.c
@@ -25,20 +25,26 @@
#include <net/ethernet.h>
#include <arpa/inet.h>
+#include "sd-lldp.h"
+#include "sd-event.h"
+#include "event-util.h"
#include "macro.h"
#include "lldp.h"
#include "lldp-tlv.h"
+#include "lldp-network.h"
#define TEST_LLDP_PORT "em1"
#define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
#define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
+static int test_fd[2];
+
static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
};
static int lldp_build_tlv_packet(tlv_packet **ret) {
- _cleanup_tlv_packet_free_ tlv_packet *m = NULL;
+ _cleanup_lldp_packet_unref_ tlv_packet *m = NULL;
const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
struct ether_header ether = {
.ether_type = htons(ETHERTYPE_LLDP),
@@ -202,6 +208,15 @@ static int lldp_parse_ttl_tlv(tlv_packet *m) {
return 0;
}
+static int lldp_get_destination_type(tlv_packet *m) {
+ int dest;
+
+ assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0);
+ assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE);
+
+ return 0;
+}
+
static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
uint8_t subtype;
@@ -212,20 +227,241 @@ static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
assert_se(lldp_parse_ttl_tlv(m) >= 0);
assert_se(lldp_parse_system_desc_tlv(m) >= 0);
+ assert_se(lldp_get_destination_type(m) >= 0);
+
return 0;
}
-int main(int argc, char *argv[]) {
- _cleanup_tlv_packet_free_ tlv_packet *tlv = NULL;
+static void test_parser(void) {
+ _cleanup_lldp_packet_unref_ tlv_packet *tlv = NULL;
/* form a packet */
lldp_build_tlv_packet(&tlv);
-
/* parse the packet */
tlv_packet_parse_pdu(tlv, tlv->length);
-
/* verify */
lldp_parse_tlv_packet(tlv, tlv->length);
+}
+
+int lldp_network_bind_raw_socket(int ifindex) {
+ if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
+ return -errno;
+
+ return test_fd[0];
+}
+
+static int lldp_handler_calls;
+static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
+ lldp_handler_calls++;
+}
+
+static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) {
+ int r;
+
+ r = sd_lldp_new(42, "dummy", &mac_addr, lldp);
+ if (r)
+ return r;
+
+ r = sd_lldp_attach_event(*lldp, e, 0);
+ if (r)
+ return r;
+
+ r = sd_lldp_set_callback(*lldp, cb, cb_data);
+ if (r)
+ return r;
+
+ r = sd_lldp_start(*lldp);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int stop_lldp(sd_lldp *lldp) {
+ int r;
+
+ r = sd_lldp_stop(lldp);
+ if (r)
+ return r;
+
+ r = sd_lldp_detach_event(lldp);
+ if (r)
+ return r;
+
+ sd_lldp_free(lldp);
+ safe_close(test_fd[1]);
+
+ return 0;
+}
+
+static void test_receive_basic_packet(sd_event *e) {
+ sd_lldp *lldp;
+ sd_lldp_packet **packets;
+ uint8_t type, *data;
+ uint16_t length, ttl;
+ int dest_type;
+ char *str;
+ uint8_t frame[] = {
+ /* Ethernet header */
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
+ 0x88, 0xcc, /* Ethertype */
+ /* LLDP mandatory TLVs */
+ 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
+ 0x03, 0x04, 0x05,
+ 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
+ 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
+ /* LLDP optional TLVs */
+ 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */
+ 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */
+ 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */
+ 0x00, 0x00 /* End Of LLDPDU */
+ };
+
+ lldp_handler_calls = 0;
+ assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
+
+ assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
+ sd_event_run(e, 0);
+ assert_se(lldp_handler_calls == 1);
+ assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
+
+ assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0);
+ assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
+ assert_se(length == ETH_ALEN);
+ assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));
+
+ assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0);
+ assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME);
+ assert_se(length == 3);
+ assert_se(strneq((char *) data, "1/3", 3));
+
+ assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0);
+ assert_se(length == 4);
+ assert_se(strneq(str, "Port", 4));
+
+ assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0);
+ assert_se(length == 3);
+ assert_se(strneq(str, "SYS", 3));
+
+ assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0);
+ assert_se(length == 4); /* This is the real length in the TLV packet */
+ assert_se(strneq(str, "foo", 3));
+
+ assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0);
+ assert_se(ttl == 120);
+
+ assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0);
+ assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE);
+
+ sd_lldp_packet_unref(packets[0]);
+ free(packets);
+
+ assert_se(stop_lldp(lldp) == 0);
+}
+
+static void test_receive_incomplete_packet(sd_event *e) {
+ sd_lldp *lldp;
+ sd_lldp_packet **packets;
+ uint8_t frame[] = {
+ /* Ethernet header */
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
+ 0x88, 0xcc, /* Ethertype */
+ /* LLDP mandatory TLVs */
+ 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
+ 0x03, 0x04, 0x05,
+ 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */
+ /* Missing TTL */
+ 0x00, 0x00 /* End Of LLDPDU */
+ };
+
+ lldp_handler_calls = 0;
+ assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
+
+ assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
+ sd_event_run(e, 0);
+ assert_se(lldp_handler_calls == 0);
+ assert_se(sd_lldp_get_packets(lldp, &packets) == 0);
+
+ assert_se(stop_lldp(lldp) == 0);
+}
+
+static void test_receive_oui_packet(sd_event *e) {
+ sd_lldp *lldp;
+ sd_lldp_packet **packets;
+ uint32_t id32;
+ uint16_t id16, len;
+ uint8_t flags;
+ char *str;
+ uint8_t frame[] = {
+ /* Ethernet header */
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
+ 0x88, 0xcc, /* Ethertype */
+ /* LLDP mandatory TLVs */
+ 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */
+ 0x03, 0x04, 0x05,
+ 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */
+ 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/
+ /* LLDP optional TLVs */
+ 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */
+ 0x12, 0x34,
+ 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */
+ 0x01, 0x77, 0x88,
+ 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */
+ 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61,
+ 0x6e, 0x35, 0x31,
+ 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */
+ 0x01, 0x02,
+ 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */
+ 0x01, 0x00, 0x14, 0x00, 0x12,
+ 0x00, 0x00 /* End of LLDPDU */
+ };
+
+ lldp_handler_calls = 0;
+ assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
+
+ assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
+ sd_event_run(e, 0);
+ assert_se(lldp_handler_calls == 1);
+ assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
+
+ assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0);
+ assert_se(id16 == 0x1234);
+
+ assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0);
+ assert_se(flags == 1);
+ assert_se(id16 == 0x7788);
+
+ assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0);
+ assert_se(id16 == 0x1234);
+ assert_se(len == 6);
+ assert_se(strneq(str, "Vlan51", 6));
+
+ assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0);
+ assert_se(id16 == 0x0102);
+
+ assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0);
+ assert_se(flags == 1);
+ assert_se(id32 == 0x00140012);
+
+ sd_lldp_packet_unref(packets[0]);
+ free(packets);
+
+ assert_se(stop_lldp(lldp) == 0);
+}
+
+int main(int argc, char *argv[]) {
+ _cleanup_event_unref_ sd_event *e = NULL;
+
+ test_parser();
+
+ /* LLDP reception tests */
+ assert_se(sd_event_new(&e) == 0);
+ test_receive_basic_packet(e);
+ test_receive_incomplete_packet(e);
+ test_receive_oui_packet(e);
return 0;
}
diff --git a/src/libsystemd-network/test-pppoe.c b/src/libsystemd-network/test-pppoe.c
index 72878f4b51..6ea460d9ac 100644
--- a/src/libsystemd-network/test-pppoe.c
+++ b/src/libsystemd-network/test-pppoe.c
@@ -19,19 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
-#include <unistd.h>
-
#include <linux/veth.h>
#include <net/if.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sched.h>
-#include "util.h"
#include "sd-event.h"
-#include "event-util.h"
#include "sd-netlink.h"
#include "sd-pppoe.h"
+
+#include "event-util.h"
#include "process-util.h"
+#include "util.h"
static void pppoe_handler(sd_pppoe *ppp, int event, void *userdata) {
static int pppoe_state = -1;
@@ -41,12 +42,12 @@ static void pppoe_handler(sd_pppoe *ppp, int event, void *userdata) {
assert_se(e);
switch (event) {
- case PPPOE_EVENT_RUNNING:
+ case SD_PPPOE_EVENT_RUNNING:
assert_se(pppoe_state == -1);
log_info("running");
break;
- case PPPOE_EVENT_STOPPED:
- assert_se(pppoe_state == PPPOE_EVENT_RUNNING);
+ case SD_PPPOE_EVENT_STOPPED:
+ assert_se(pppoe_state == SD_PPPOE_EVENT_RUNNING);
log_info("stopped");
assert_se(sd_event_exit(e, 0) >= 0);
break;
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index d5ad127bcb..043ff13e6f 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -473,3 +473,11 @@ global:
sd_pid_get_cgroup;
sd_peer_get_cgroup;
} LIBSYSTEMD_222;
+
+LIBSYSTEMD_227 {
+global:
+ sd_bus_default_flush_close;
+ sd_bus_path_decode_many;
+ sd_bus_path_encode_many;
+ sd_listen_fds_with_names;
+} LIBSYSTEMD_226;
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
index 5c607f49b1..435ec92d6f 100644
--- a/src/libsystemd/sd-bus/bus-container.c
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -217,15 +217,8 @@ int bus_container_connect_kernel(sd_bus *b) {
_exit(EXIT_FAILURE);
}
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
- if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
+ r = send_one_fd(pair[1], fd, 0);
+ if (r < 0)
_exit(EXIT_FAILURE);
_exit(EXIT_SUCCESS);
diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c
index a6b05eb88d..8833b9c677 100644
--- a/src/libsystemd/sd-bus/bus-dump.c
+++ b/src/libsystemd/sd-bus/bus-dump.c
@@ -73,8 +73,8 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
"%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64,
m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
- m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(),
- ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
+ m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_normal(),
+ ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(),
m->header->endian,
m->header->flags,
m->header->version,
@@ -93,15 +93,15 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
fputs("\n", f);
if (m->sender)
- fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off());
+ fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_normal());
if (m->destination)
- fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off());
+ fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_normal());
if (m->path)
- fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off());
+ fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_normal());
if (m->interface)
- fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off());
+ fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_normal());
if (m->member)
- fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off());
+ fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_normal());
if (m->sender || m->destination || m->path || m->interface || m->member)
fputs("\n", f);
@@ -110,8 +110,8 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
fprintf(f,
" ErrorName=%s%s%s"
" ErrorMessage=%s\"%s\"%s\n",
- ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(),
- ansi_highlight_red(), strna(m->error.message), ansi_highlight_off());
+ ansi_highlight_red(), strna(m->error.name), ansi_normal(),
+ ansi_highlight_red(), strna(m->error.message), ansi_normal());
if (m->monotonic != 0)
fprintf(f, " Monotonic="USEC_FMT, m->monotonic);
@@ -211,55 +211,55 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
switch (type) {
case SD_BUS_TYPE_BYTE:
- fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
+ fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_normal());
break;
case SD_BUS_TYPE_BOOLEAN:
- fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
+ fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_normal());
break;
case SD_BUS_TYPE_INT16:
- fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
+ fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_normal());
break;
case SD_BUS_TYPE_UINT16:
- fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
+ fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_normal());
break;
case SD_BUS_TYPE_INT32:
- fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
+ fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_normal());
break;
case SD_BUS_TYPE_UINT32:
- fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
+ fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_normal());
break;
case SD_BUS_TYPE_INT64:
- fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_highlight_off());
+ fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_normal());
break;
case SD_BUS_TYPE_UINT64:
- fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_highlight_off());
+ fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_normal());
break;
case SD_BUS_TYPE_DOUBLE:
- fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
+ fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_normal());
break;
case SD_BUS_TYPE_STRING:
- fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
+ fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal());
break;
case SD_BUS_TYPE_OBJECT_PATH:
- fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
+ fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal());
break;
case SD_BUS_TYPE_SIGNATURE:
- fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
+ fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_normal());
break;
case SD_BUS_TYPE_UNIX_FD:
- fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
+ fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_normal());
break;
default:
@@ -327,7 +327,7 @@ static void dump_capabilities(
fputs("\n", f);
if (!terse)
- fputs(ansi_highlight_off(), f);
+ fputs(ansi_normal(), f);
}
int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
@@ -352,7 +352,7 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
prefix = "";
color = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
suffix = strjoina(off, "\n");
}
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 7af61a9433..e399701beb 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -396,6 +396,6 @@ int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error);
#define bus_assert_return(expr, r, error) \
do { \
- if (!assert_log(expr)) \
+ if (!assert_log(expr, #expr)) \
return sd_bus_error_set_errno(error, r); \
} while (false)
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index 1d061cb9cf..728f20447a 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -1578,25 +1578,14 @@ _public_ int sd_bus_add_fallback(
return bus_add_object(bus, slot, true, prefix, callback, userdata);
}
-static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void vtable_member_hash_func(const void *a, struct siphash *state) {
const struct vtable_member *m = a;
- uint8_t hash_key2[HASH_KEY_SIZE];
- unsigned long ret;
assert(m);
- ret = string_hash_func(m->path, hash_key);
-
- /* Use a slightly different hash key for the interface */
- memcpy(hash_key2, hash_key, HASH_KEY_SIZE);
- hash_key2[0]++;
- ret ^= string_hash_func(m->interface, hash_key2);
-
- /* And an even different one for the member */
- hash_key2[0]++;
- ret ^= string_hash_func(m->member, hash_key2);
-
- return ret;
+ string_hash_func(m->path, state);
+ string_hash_func(m->interface, state);
+ string_hash_func(m->member, state);
}
static int vtable_member_compare_func(const void *a, const void *b) {
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index 735a775cb4..d0b1e3d7dc 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -985,7 +985,7 @@ int bus_socket_read_message(sd_bus *bus) {
return -EIO;
}
- f = realloc(bus->fds, sizeof(int) + (bus->n_fds + n));
+ f = realloc(bus->fds, sizeof(int) * (bus->n_fds + n));
if (!f) {
close_many((int*) CMSG_DATA(cmsg), n);
return -ENOMEM;
diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c
index 9a6d338231..49c97af339 100644
--- a/src/libsystemd/sd-bus/busctl.c
+++ b/src/libsystemd/sd-bus/busctl.c
@@ -21,22 +21,21 @@
#include <getopt.h>
-#include "strv.h"
-#include "util.h"
-#include "log.h"
-#include "build.h"
-#include "pager.h"
-#include "path-util.h"
-#include "set.h"
-
#include "sd-bus.h"
-#include "bus-internal.h"
-#include "bus-util.h"
+
#include "bus-dump.h"
+#include "bus-internal.h"
#include "bus-signature.h"
#include "bus-type.h"
+#include "bus-util.h"
#include "busctl-introspect.h"
+#include "log.h"
+#include "pager.h"
+#include "path-util.h"
+#include "set.h"
+#include "strv.h"
#include "terminal-util.h"
+#include "util.h"
static bool arg_no_pager = false;
static bool arg_legend = true;
@@ -449,7 +448,7 @@ static int tree(sd_bus *bus, char **argv) {
if (not_first)
printf("\n");
- printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
+ printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
q = tree_one(bus, *i, NULL, true);
if (q < 0 && r >= 0)
@@ -466,7 +465,7 @@ static int tree(sd_bus *bus, char **argv) {
if (argv[2]) {
pager_open_if_enabled();
- printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_highlight_off());
+ printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
}
q = tree_one(bus, *i, NULL, !!argv[2]);
@@ -629,22 +628,24 @@ typedef struct Member {
uint64_t flags;
} Member;
-static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) {
+static void member_hash_func(const void *p, struct siphash *state) {
const Member *m = p;
- unsigned long ul;
+ uint64_t arity = 1;
assert(m);
assert(m->type);
- ul = string_hash_func(m->type, hash_key);
+ string_hash_func(m->type, state);
+
+ arity += !!m->name + !!m->interface;
+
+ uint64_hash_func(&arity, state);
if (m->name)
- ul ^= string_hash_func(m->name, hash_key);
+ string_hash_func(m->name, state);
if (m->interface)
- ul ^= string_hash_func(m->interface, hash_key);
-
- return ul;
+ string_hash_func(m->interface, state);
}
static int member_compare_func(const void *a, const void *b) {
@@ -1052,7 +1053,7 @@ static int introspect(sd_bus *bus, char **argv) {
is_interface ? ansi_highlight() : "",
is_interface ? "" : ".",
- !is_interface + (int) name_width, strdash(streq_ptr(m->type, "interface") ? m->interface : m->name),
- is_interface ? ansi_highlight_off() : "",
+ is_interface ? ansi_normal() : "",
(int) type_width, strdash(m->type),
(int) signature_width, strdash(m->signature),
(int) result_width, rv,
@@ -1096,6 +1097,15 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL
if (r < 0)
return log_error_errno(r, "Failed to add match: %m");
+ free(m);
+ m = strjoin("destination='", *i, "'", NULL);
+ if (!m)
+ return log_oom();
+
+ r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add match: %m");
+
added_something = true;
}
@@ -1196,15 +1206,15 @@ static int status(sd_bus *bus, char *argv[]) {
r = sd_bus_get_address(bus, &address);
if (r >= 0)
- printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_highlight_off());
+ printf("BusAddress=%s%s%s\n", ansi_highlight(), address, ansi_normal());
r = sd_bus_get_scope(bus, &scope);
if (r >= 0)
- printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_highlight_off());
+ printf("BusScope=%s%s%s\n", ansi_highlight(), scope, ansi_normal());
r = sd_bus_get_bus_id(bus, &bus_id);
if (r >= 0)
- printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_highlight_off());
+ printf("BusID=%s" SD_ID128_FORMAT_STR "%s\n", ansi_highlight(), SD_ID128_FORMAT_VAL(bus_id), ansi_normal());
r = sd_bus_get_owner_creds(
bus,
@@ -1777,9 +1787,7 @@ static int parse_argv(int argc, char *argv[]) {
return help();
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 25fd3b5c52..a23f7257fa 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -69,6 +69,10 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec);
static int attach_io_events(sd_bus *b);
static void detach_io_events(sd_bus *b);
+static thread_local sd_bus *default_system_bus = NULL;
+static thread_local sd_bus *default_user_bus = NULL;
+static thread_local sd_bus *default_starter_bus = NULL;
+
static void bus_close_fds(sd_bus *b) {
assert(b);
@@ -3348,14 +3352,11 @@ static int bus_default(int (*bus_open)(sd_bus **), sd_bus **default_bus, sd_bus
}
_public_ int sd_bus_default_system(sd_bus **ret) {
- static thread_local sd_bus *default_system_bus = NULL;
-
return bus_default(sd_bus_open_system, &default_system_bus, ret);
}
-_public_ int sd_bus_default_user(sd_bus **ret) {
- static thread_local sd_bus *default_user_bus = NULL;
+_public_ int sd_bus_default_user(sd_bus **ret) {
return bus_default(sd_bus_open_user, &default_user_bus, ret);
}
@@ -3382,7 +3383,6 @@ _public_ int sd_bus_default(sd_bus **ret) {
e = secure_getenv("DBUS_STARTER_ADDRESS");
if (e) {
- static thread_local sd_bus *default_starter_bus = NULL;
return bus_default(sd_bus_open, &default_starter_bus, ret);
}
@@ -3454,6 +3454,171 @@ _public_ int sd_bus_path_decode(const char *path, const char *prefix, char **ext
return 1;
}
+_public_ int sd_bus_path_encode_many(char **out, const char *path_template, ...) {
+ _cleanup_strv_free_ char **labels = NULL;
+ char *path, *path_pos, **label_pos;
+ const char *sep, *template_pos;
+ size_t path_length;
+ va_list list;
+ int r;
+
+ assert_return(out, -EINVAL);
+ assert_return(path_template, -EINVAL);
+
+ path_length = strlen(path_template);
+
+ va_start(list, path_template);
+ for (sep = strchr(path_template, '%'); sep; sep = strchr(sep + 1, '%')) {
+ const char *arg;
+ char *label;
+
+ arg = va_arg(list, const char *);
+ if (!arg) {
+ va_end(list);
+ return -EINVAL;
+ }
+
+ label = bus_label_escape(arg);
+ if (!label) {
+ va_end(list);
+ return -ENOMEM;
+ }
+
+ r = strv_consume(&labels, label);
+ if (r < 0) {
+ va_end(list);
+ return r;
+ }
+
+ /* add label length, but account for the format character */
+ path_length += strlen(label) - 1;
+ }
+ va_end(list);
+
+ path = malloc(path_length + 1);
+ if (!path)
+ return -ENOMEM;
+
+ path_pos = path;
+ label_pos = labels;
+
+ for (template_pos = path_template; *template_pos; ) {
+ sep = strchrnul(template_pos, '%');
+ path_pos = mempcpy(path_pos, template_pos, sep - template_pos);
+ if (!*sep)
+ break;
+
+ path_pos = stpcpy(path_pos, *label_pos++);
+ template_pos = sep + 1;
+ }
+
+ *path_pos = 0;
+ *out = path;
+ return 0;
+}
+
+_public_ int sd_bus_path_decode_many(const char *path, const char *path_template, ...) {
+ _cleanup_strv_free_ char **labels = NULL;
+ const char *template_pos, *path_pos;
+ char **label_pos;
+ va_list list;
+ int r;
+
+ /*
+ * This decodes an object-path based on a template argument. The
+ * template consists of a verbatim path, optionally including special
+ * directives:
+ *
+ * - Each occurrence of '%' in the template matches an arbitrary
+ * substring of a label in the given path. At most one such
+ * directive is allowed per label. For each such directive, the
+ * caller must provide an output parameter (char **) via va_arg. If
+ * NULL is passed, the given label is verified, but not returned.
+ * For each matched label, the *decoded* label is stored in the
+ * passed output argument, and the caller is responsible to free
+ * it. Note that the output arguments are only modified if the
+ * actualy path matched the template. Otherwise, they're left
+ * untouched.
+ *
+ * This function returns <0 on error, 0 if the path does not match the
+ * template, 1 if it matched.
+ */
+
+ assert_return(path, -EINVAL);
+ assert_return(path_template, -EINVAL);
+
+ path_pos = path;
+
+ for (template_pos = path_template; *template_pos; ) {
+ const char *sep;
+ size_t length;
+ char *label;
+
+ /* verify everything until the next '%' matches verbatim */
+ sep = strchrnul(template_pos, '%');
+ length = sep - template_pos;
+ if (strncmp(path_pos, template_pos, length))
+ return 0;
+
+ path_pos += length;
+ template_pos += length;
+
+ if (!*template_pos)
+ break;
+
+ /* We found the next '%' character. Everything up until here
+ * matched. We now skip ahead to the end of this label and make
+ * sure it matches the tail of the label in the path. Then we
+ * decode the string in-between and save it for later use. */
+
+ ++template_pos; /* skip over '%' */
+
+ sep = strchrnul(template_pos, '/');
+ length = sep - template_pos; /* length of suffix to match verbatim */
+
+ /* verify the suffixes match */
+ sep = strchrnul(path_pos, '/');
+ if (sep - path_pos < (ssize_t)length ||
+ strncmp(sep - length, template_pos, length))
+ return 0;
+
+ template_pos += length; /* skip over matched label */
+ length = sep - path_pos - length; /* length of sub-label to decode */
+
+ /* store unescaped label for later use */
+ label = bus_label_unescape_n(path_pos, length);
+ if (!label)
+ return -ENOMEM;
+
+ r = strv_consume(&labels, label);
+ if (r < 0)
+ return r;
+
+ path_pos = sep; /* skip decoded label and suffix */
+ }
+
+ /* end of template must match end of path */
+ if (*path_pos)
+ return 0;
+
+ /* copy the labels over to the caller */
+ va_start(list, path_template);
+ for (label_pos = labels; label_pos && *label_pos; ++label_pos) {
+ char **arg;
+
+ arg = va_arg(list, char **);
+ if (arg)
+ *arg = *label_pos;
+ else
+ free(*label_pos);
+ }
+ va_end(list);
+
+ free(labels);
+ labels = NULL;
+ return 1;
+}
+
_public_ int sd_bus_try_close(sd_bus *bus) {
int r;
@@ -3605,3 +3770,20 @@ _public_ int sd_bus_is_monitor(sd_bus *bus) {
return !!(bus->hello_flags & KDBUS_HELLO_MONITOR);
}
+
+static void flush_close(sd_bus *bus) {
+ if (!bus)
+ return;
+
+ /* Flushes and closes the specified bus. We take a ref before,
+ * to ensure the flushing does not cause the bus to be
+ * unreferenced. */
+
+ sd_bus_flush_close_unref(sd_bus_ref(bus));
+}
+
+_public_ void sd_bus_default_flush_close(void) {
+ flush_close(default_starter_bus);
+ flush_close(default_user_bus);
+ flush_close(default_system_bus);
+}
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
index b203707f27..ff6bba5988 100644
--- a/src/libsystemd/sd-bus/test-bus-marshal.c
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -66,6 +66,36 @@ static void test_bus_path_encode(void) {
assert_se(sd_bus_path_decode(e, "/foo/bar", &f) > 0 && streq(f, "foo.bar"));
}
+static void test_bus_path_encode_many(void) {
+ _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL;
+
+ assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/prefix/bar", "/prefix/%bar", NULL) == 1);
+ assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%/suffix", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/prefix/foobar/suffix", "/prefix/%/suffix", &a) == 1 && streq_ptr(a, "foobar"));
+ assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", &b, &c) == 1 && streq_ptr(b, "foo") && streq_ptr(c, "bar"));
+ assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", NULL, &d) == 1 && streq_ptr(d, "bar"));
+
+ assert_se(sd_bus_path_decode_many("/foo/bar", "/foo/bar/%", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar%", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/bar", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%bar", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar/suffix") == 1);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%%/suffix", NULL, NULL) == 0); /* multiple '%' are treated verbatim */
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffi", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffix", &e) == 1 && streq_ptr(e, "bar"));
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/%", NULL, NULL) == 1);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/%", NULL, NULL, NULL) == 1);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%/%/%", NULL, NULL, NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%", NULL, NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/", NULL, NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%", NULL) == 0);
+ assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%", NULL) == 0);
+
+ assert_se(sd_bus_path_encode_many(&f, "/prefix/one_%_two/mid/three_%_four/suffix", "foo", "bar") >= 0 && streq_ptr(f, "/prefix/one_foo_two/mid/three_bar_four/suffix"));
+}
+
static void test_bus_label_escape_one(const char *a, const char *b) {
_cleanup_free_ char *t = NULL, *x = NULL, *y = NULL;
@@ -393,6 +423,7 @@ int main(int argc, char *argv[]) {
test_bus_label_escape();
test_bus_path_encode();
test_bus_path_encode_unique();
+ test_bus_path_encode_many();
return 0;
}
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index 9ec73406c6..ae534ba5b9 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -19,25 +19,37 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <stdlib.h>
#include <errno.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stddef.h>
#include <limits.h>
#include <mqueue.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
-#include "util.h"
#include "path-util.h"
#include "socket-util.h"
+#include "strv.h"
+#include "util.h"
+
#include "sd-daemon.h"
+static void unsetenv_all(bool unset_environment) {
+
+ if (!unset_environment)
+ return;
+
+ unsetenv("LISTEN_PID");
+ unsetenv("LISTEN_FDS");
+ unsetenv("LISTEN_FDNAMES");
+}
+
_public_ int sd_listen_fds(int unset_environment) {
const char *e;
unsigned n;
@@ -79,12 +91,49 @@ _public_ int sd_listen_fds(int unset_environment) {
r = (int) n;
finish:
- if (unset_environment) {
- unsetenv("LISTEN_PID");
- unsetenv("LISTEN_FDS");
+ unsetenv_all(unset_environment);
+ return r;
+}
+
+_public_ int sd_listen_fds_with_names(int unset_environment, char ***names) {
+ _cleanup_strv_free_ char **l = NULL;
+ bool have_names;
+ int n_names = 0, n_fds;
+ const char *e;
+ int r;
+
+ if (!names)
+ return sd_listen_fds(unset_environment);
+
+ e = getenv("LISTEN_FDNAMES");
+ if (e) {
+ n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
+ if (n_names < 0) {
+ unsetenv_all(unset_environment);
+ return n_names;
+ }
+
+ have_names = true;
+ } else
+ have_names = false;
+
+ n_fds = sd_listen_fds(unset_environment);
+ if (n_fds <= 0)
+ return n_fds;
+
+ if (have_names) {
+ if (n_names != n_fds)
+ return -EINVAL;
+ } else {
+ r = strv_extend_n(&l, "unknown", n_fds);
+ if (r < 0)
+ return r;
}
- return r;
+ *names = l;
+ l = NULL;
+
+ return n_fds;
}
_public_ int sd_is_fifo(int fd, const char *path) {
@@ -310,10 +359,15 @@ _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path
_public_ int sd_is_mq(int fd, const char *path) {
struct mq_attr attr;
- assert_return(fd >= 0, -EBADF);
+ /* Check that the fd is valid */
+ assert_return(fcntl(fd, F_GETFD) >= 0, -errno);
- if (mq_getattr(fd, &attr) < 0)
+ if (mq_getattr(fd, &attr) < 0) {
+ if (errno == EBADF)
+ /* A non-mq fd (or an invalid one, but we ruled that out above) */
+ return 0;
return -errno;
+ }
if (path) {
char fpath[PATH_MAX];
@@ -396,9 +450,11 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
if (n_fds > 0 || have_pid) {
/* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
- msghdr.msg_controllen = (n_fds ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
- CMSG_SPACE(sizeof(struct ucred)) * have_pid;
- msghdr.msg_control = alloca(msghdr.msg_controllen);
+ msghdr.msg_controllen =
+ (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
+ (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
+
+ msghdr.msg_control = alloca0(msghdr.msg_controllen);
cmsg = CMSG_FIRSTHDR(&msghdr);
if (n_fds > 0) {
@@ -498,16 +554,11 @@ _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
}
_public_ int sd_booted(void) {
- struct stat st;
-
/* We test whether the runtime unit file directory has been
* created. This takes place in mount-setup.c, so is
* guaranteed to happen very early during boot. */
- if (lstat("/run/systemd/system/", &st) < 0)
- return 0;
-
- return !!S_ISDIR(st.st_mode);
+ return laccess("/run/systemd/system/", F_OK) >= 0;
}
_public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) {
diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c
index 5eb37e16cb..45a4d12eb7 100644
--- a/src/libsystemd/sd-device/device-enumerator.c
+++ b/src/libsystemd/sd-device/device-enumerator.c
@@ -812,10 +812,8 @@ static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
if (access("/sys/subsystem", F_OK) >= 0) {
/* we have /subsystem/, forget all the old stuff */
r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL);
- if (r < 0) {
- log_debug("device-enumerator: failed to scan /sys/subsystem: %s", strerror(-r));
- return r;
- }
+ if (r < 0)
+ return log_debug_errno(r, "device-enumerator: failed to scan /sys/subsystem: %m");
} else {
int k;
diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c
index 0ec9667744..b5215cb9b5 100644
--- a/src/libsystemd/sd-device/device-private.c
+++ b/src/libsystemd/sd-device/device-private.c
@@ -200,10 +200,8 @@ static int device_read_db(sd_device *device) {
if (r < 0) {
if (r == -ENOENT)
return 0;
- else {
- log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
- return r;
- }
+ else
+ return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
}
/* devices with a database entry are initialized */
@@ -247,7 +245,7 @@ static int device_read_db(sd_device *device) {
db[i] = '\0';
r = handle_db_line(device, key, value);
if (r < 0)
- log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
+ log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
state = PRE_KEY;
}
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index 7cea5a0746..e46546ed91 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -169,11 +169,10 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
/* the device does not exist (any more?) */
return -ENODEV;
- log_debug("sd-device: could not canonicalize '%s': %m", _syspath);
- return -errno;
+ return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath);
}
} else if (r < 0) {
- log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r));
+ log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath);
return r;
}
@@ -296,15 +295,27 @@ _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *s
} else
return -EINVAL;
} else {
- syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname);
+ char *name;
+ size_t len = 0;
+
+ /* translate sysname back to sysfs filename */
+ name = strdupa(sysname);
+ while (name[len] != '\0') {
+ if (name[len] == '/')
+ name[len] = '!';
+
+ len ++;
+ }
+
+ syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name);
if (access(syspath, F_OK) >= 0)
return sd_device_new_from_syspath(ret, syspath);
- syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname);
+ syspath = strjoina("/sys/bus/", subsystem, "/devices/", name);
if (access(syspath, F_OK) >= 0)
return sd_device_new_from_syspath(ret, syspath);
- syspath = strjoina("/sys/class/", subsystem, "/", sysname);
+ syspath = strjoina("/sys/class/", subsystem, "/", name);
if (access(syspath, F_OK) >= 0)
return sd_device_new_from_syspath(ret, syspath);
}
@@ -516,7 +527,7 @@ int device_read_uevent_file(sd_device *device) {
/* some devices may not have uevent files, see set_syspath() */
return 0;
else if (r < 0) {
- log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r));
+ log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path);
return r;
}
@@ -555,7 +566,7 @@ int device_read_uevent_file(sd_device *device) {
r = handle_uevent_line(device, key, value, &major, &minor);
if (r < 0)
- log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r));
+ log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value);
state = PRE_KEY;
}
@@ -569,7 +580,7 @@ int device_read_uevent_file(sd_device *device) {
if (major) {
r = device_set_devnum(device, major, minor);
if (r < 0)
- log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r));
+ log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path);
}
return 0;
@@ -1271,10 +1282,8 @@ int device_read_db_aux(sd_device *device, bool force) {
if (r < 0) {
if (r == -ENOENT)
return 0;
- else {
- log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r));
- return r;
- }
+ else
+ return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path);
}
/* devices with a database entry are initialized */
@@ -1318,7 +1327,7 @@ int device_read_db_aux(sd_device *device, bool force) {
db[i] = '\0';
r = handle_db_line(device, key, value);
if (r < 0)
- log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r));
+ log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value);
state = PRE_KEY;
}
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index fd39a56225..1a82c4c940 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -242,12 +242,6 @@ static int pending_prioq_compare(const void *a, const void *b) {
if (x->pending_iteration > y->pending_iteration)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
@@ -257,6 +251,12 @@ static int prepare_prioq_compare(const void *a, const void *b) {
assert(x->prepare);
assert(y->prepare);
+ /* Enabled ones first */
+ if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
+ return -1;
+ if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
+ return 1;
+
/* Move most recently prepared ones last, so that we can stop
* preparing as soon as we hit one that has already been
* prepared in the current iteration */
@@ -265,24 +265,12 @@ static int prepare_prioq_compare(const void *a, const void *b) {
if (x->prepare_iteration > y->prepare_iteration)
return 1;
- /* Enabled ones first */
- if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
- return -1;
- if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
- return 1;
-
/* Lower priority values first */
if (x->priority < y->priority)
return -1;
if (x->priority > y->priority)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
@@ -310,12 +298,6 @@ static int earliest_time_prioq_compare(const void *a, const void *b) {
if (x->time.next > y->time.next)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
@@ -343,12 +325,6 @@ static int latest_time_prioq_compare(const void *a, const void *b) {
if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
@@ -370,12 +346,6 @@ static int exit_prioq_compare(const void *a, const void *b) {
if (x->priority > y->priority)
return 1;
- /* Stability for the rest */
- if (x < y)
- return -1;
- if (x > y)
- return 1;
-
return 0;
}
diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h
index fedccdec72..13fddfc8ad 100644
--- a/src/libsystemd/sd-hwdb/hwdb-internal.h
+++ b/src/libsystemd/sd-hwdb/hwdb-internal.h
@@ -19,6 +19,7 @@
#pragma once
#include "sparse-endian.h"
+#include "util.h"
#define HWDB_SIG { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' }
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index 46f2181ea8..eb539ad318 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -28,7 +28,7 @@
#include "sd-id128.h"
#include "random-util.h"
-_public_ char *sd_id128_to_string(sd_id128_t id, char s[33]) {
+_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) {
unsigned n;
assert_return(s, NULL);
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 0d8e37b856..cf693de5fb 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -149,6 +149,15 @@ int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
return 0;
}
+int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
+ assert_return(m, -EINVAL);
+ assert_return(flags, -EINVAL);
+
+ m->hdr->nlmsg_flags = flags;
+
+ return 0;
+}
+
int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
assert_return(m, -EINVAL);
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index 2128329191..4a5340e659 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -97,7 +97,7 @@ static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = {
[IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 },
};
-static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
+static const NLType rtnl_link_bridge_management_types[IFLA_BRIDGE_MAX + 1] = {
[IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 },
[IFLA_BRIDGE_MODE] = { .type = NETLINK_TYPE_U16 },
/*
@@ -106,6 +106,15 @@ static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = {
*/
};
+static const NLType rtnl_link_info_data_bridge_types[IFLA_BR_MAX + 1] = {
+ [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 },
+};
+
static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = {
[IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 },
/*
diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c
index 2f31f4ee69..03049bd31f 100644
--- a/src/libsystemd/sd-netlink/rtnl-message.c
+++ b/src/libsystemd/sd-netlink/rtnl-message.c
@@ -99,6 +99,66 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
return 0;
}
+int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(protocol, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *protocol = rtm->rtm_protocol;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(scope, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *scope = rtm->rtm_scope;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(tos, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *tos = rtm->rtm_tos;
+
+ return 0;
+}
+
+int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+ assert_return(table, -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ *table = rtm->rtm_table;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
struct rtmsg *rtm;
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index d248869c8d..f4a0a358a9 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -856,8 +856,6 @@ int sd_netlink_add_match(sd_netlink *rtnl,
switch (type) {
case RTM_NEWLINK:
- case RTM_SETLINK:
- case RTM_GETLINK:
case RTM_DELLINK:
r = socket_join_broadcast_group(rtnl, RTNLGRP_LINK);
if (r < 0)
@@ -865,7 +863,6 @@ int sd_netlink_add_match(sd_netlink *rtnl,
break;
case RTM_NEWADDR:
- case RTM_GETADDR:
case RTM_DELADDR:
r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR);
if (r < 0)
@@ -876,6 +873,16 @@ int sd_netlink_add_match(sd_netlink *rtnl,
return r;
break;
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_ROUTE);
+ if (r < 0)
+ return r;
+
+ r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_ROUTE);
+ if (r < 0)
+ return r;
+ break;
default:
return -EOPNOTSUPP;
}
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index 4a91c7420a..880a1794aa 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -20,26 +20,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <ftw.h>
+#include <getopt.h>
#include <locale.h>
-#include <stdlib.h>
#include <stdbool.h>
-#include <getopt.h>
+#include <stdlib.h>
#include <string.h>
-#include <ftw.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
#include "bus-error.h"
-#include "util.h"
-#include "spawn-polkit-agent.h"
-#include "build.h"
-#include "strv.h"
-#include "pager.h"
-#include "set.h"
+#include "bus-util.h"
#include "def.h"
-#include "virt.h"
#include "fileio.h"
#include "locale-util.h"
+#include "pager.h"
+#include "set.h"
+#include "spawn-polkit-agent.h"
+#include "strv.h"
+#include "util.h"
+#include "virt.h"
static bool arg_no_pager = false;
static bool arg_ask_password = true;
@@ -546,9 +546,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_CONVERT:
arg_convert = false;
@@ -678,7 +676,7 @@ int main(int argc, char*argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
diff --git a/src/login/.gitignore b/src/login/.gitignore
index 5c0b2ac68c..39088ec252 100644
--- a/src/login/.gitignore
+++ b/src/login/.gitignore
@@ -2,3 +2,4 @@
/org.freedesktop.login1.policy
/71-seat.rules
/73-seat-late.rules
+/systemd-user
diff --git a/src/login/70-power-switch.rules b/src/login/70-power-switch.rules
index 36d2a3eb40..e2855b50f7 100644
--- a/src/login/70-power-switch.rules
+++ b/src/login/70-power-switch.rules
@@ -13,6 +13,6 @@ SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="twl4030_pwrbutton", TAG+="po
SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="tps65217_pwr_but", TAG+="power-switch"
SUBSYSTEM=="input", KERNEL=="event*", ATTRS{name}=="* WMI hotkeys", TAG+="power-switch"
SUBSYSTEM=="input", KERNEL=="event*", \
- SUBSYSTEMS=="platform", DRIVERS=="gpio-keys", ATTRS{keys}=="116", TAG+="power-switch"
+ SUBSYSTEMS=="platform", DRIVERS=="gpio-keys", ATTRS{keys}=="*,116|116,*|116|*,116,*", TAG+="power-switch"
LABEL="power_switch_end"
diff --git a/src/login/inhibit.c b/src/login/inhibit.c
index c53ea8add7..e671341b42 100644
--- a/src/login/inhibit.c
+++ b/src/login/inhibit.c
@@ -19,21 +19,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fcntl.h>
#include <getopt.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <unistd.h>
-#include <fcntl.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
#include "bus-error.h"
-#include "util.h"
-#include "build.h"
-#include "strv.h"
+#include "bus-util.h"
#include "formats-util.h"
#include "process-util.h"
#include "signal-util.h"
+#include "strv.h"
+#include "util.h"
static const char* arg_what = "idle:sleep:shutdown";
static const char* arg_who = NULL;
@@ -179,9 +179,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_WHAT:
arg_what = optarg;
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index a7e64071cf..bfc8716009 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -19,31 +19,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <errno.h>
-#include <string.h>
#include <getopt.h>
#include <locale.h>
+#include <string.h>
+#include <unistd.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
#include "bus-error.h"
+#include "bus-util.h"
+#include "cgroup-show.h"
+#include "cgroup-util.h"
#include "log.h"
-#include "util.h"
+#include "logs-show.h"
#include "macro.h"
#include "pager.h"
-#include "build.h"
+#include "process-util.h"
+#include "signal-util.h"
+#include "spawn-polkit-agent.h"
#include "strv.h"
-#include "unit-name.h"
#include "sysfs-show.h"
-#include "logs-show.h"
-#include "cgroup-show.h"
-#include "cgroup-util.h"
-#include "spawn-polkit-agent.h"
-#include "verbs.h"
-#include "process-util.h"
#include "terminal-util.h"
-#include "signal-util.h"
+#include "unit-name.h"
+#include "util.h"
+#include "verbs.h"
static char **arg_property = NULL;
static bool arg_all = false;
@@ -686,19 +686,165 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line)
return 0;
}
+static int print_property(const char *name, sd_bus_message *m, const char *contents) {
+ int r;
+
+ assert(name);
+ assert(m);
+ assert(contents);
+
+ if (arg_property && !strv_find(arg_property, name))
+ /* skip what we didn't read */
+ return sd_bus_message_skip(m, contents);
+
+ switch (contents[0]) {
+
+ case SD_BUS_TYPE_STRUCT_BEGIN:
+
+ if (contents[1] == SD_BUS_TYPE_STRING && STR_IN_SET(name, "Display", "Seat", "ActiveSession")) {
+ const char *s;
+
+ r = sd_bus_message_read(m, "(so)", &s, NULL);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (arg_all || !isempty(s))
+ printf("%s=%s\n", name, s);
+
+ return 0;
+
+ } else if (contents[1] == SD_BUS_TYPE_UINT32 && streq(name, "User")) {
+ uint32_t uid;
+
+ r = sd_bus_message_read(m, "(uo)", &uid, NULL);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (!uid_is_valid(uid)) {
+ log_error("Invalid user ID: " UID_FMT, uid);
+ return -EINVAL;
+ }
+
+ printf("%s=" UID_FMT "\n", name, uid);
+
+ return 0;
+ }
+
+ break;
+
+ case SD_BUS_TYPE_ARRAY:
+
+ if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Sessions")) {
+ const char *s;
+ bool space = false;
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(so)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ printf("%s=", name);
+
+ while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
+ printf("%s%s", space ? " " : "", s);
+ space = true;
+ }
+
+ printf("\n");
+
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ return 0;
+ }
+
+ break;
+ }
+
+ r = bus_print_property(name, m, arg_all);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (r == 0) {
+ r = sd_bus_message_skip(m, contents);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ if (arg_all)
+ printf("%s=[unprintable]\n", name);
+ }
+
+ return 0;
+}
+
static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
+ _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
+ assert(bus);
+ assert(path);
+ assert(new_line);
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ path,
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ &error,
+ &reply,
+ "s", "");
+ if (r < 0)
+ return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
+
+ r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
if (*new_line)
printf("\n");
*new_line = true;
- r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
+ while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
+ const char *name, *contents;
+
+ r = sd_bus_message_read(reply, "s", &name);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_peek_type(reply, NULL, &contents);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = print_property(name, reply, contents);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(reply);
+ 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 (r < 0)
- log_error_errno(r, "Could not get properties: %m");
+ return bus_log_parse_error(r);
- return r;
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ return 0;
}
static int show_session(int argc, char *argv[], void *userdata) {
@@ -1270,9 +1416,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'p': {
r = strv_extend(&arg_property, optarg);
@@ -1398,7 +1542,7 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
diff --git a/src/login/logind-action.c b/src/login/logind-action.c
index f635fb1b63..a44e369149 100644
--- a/src/login/logind-action.c
+++ b/src/login/logind-action.c
@@ -147,7 +147,6 @@ int manager_handle_action(
offending->uid, strna(u),
offending->pid, strna(comm));
- warn_melody();
return -EPERM;
}
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 22e37a1638..aeedf68e77 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -1352,24 +1352,26 @@ static int bus_manager_log_shutdown(
return 0;
if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) {
- p = "MESSAGE=System is powering down.";
+ p = "MESSAGE=System is powering down";
q = "SHUTDOWN=power-off";
} else if (streq(unit_name, SPECIAL_HALT_TARGET)) {
- p = "MESSAGE=System is halting.";
+ p = "MESSAGE=System is halting";
q = "SHUTDOWN=halt";
} else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) {
- p = "MESSAGE=System is rebooting.";
+ p = "MESSAGE=System is rebooting";
q = "SHUTDOWN=reboot";
} else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) {
- p = "MESSAGE=System is rebooting with kexec.";
+ p = "MESSAGE=System is rebooting with kexec";
q = "SHUTDOWN=kexec";
} else {
- p = "MESSAGE=System is shutting down.";
+ p = "MESSAGE=System is shutting down";
q = NULL;
}
- if (!isempty(m->wall_message))
- p = strjoina(p, " (", m->wall_message, ")");
+ if (isempty(m->wall_message))
+ p = strjoina(p, ".");
+ else
+ p = strjoina(p, " (", m->wall_message, ").");
return log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
@@ -2586,7 +2588,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err
}
if (m->action_job && streq(m->action_job, path)) {
- log_info("Operation finished.");
+ log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what));
/* Tell people that they now may take a lock again */
send_prepare_for(m, m->action_what, false);
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 47669afdef..451954e860 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -868,12 +868,12 @@ int config_parse_tmpfs_size(
errno = 0;
ul = strtoul(rvalue, &f, 10);
if (errno != 0 || f != e) {
- log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse percentage value, ignoring: %s", rvalue);
return 0;
}
if (ul <= 0 || ul >= 100) {
- log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Percentage value out of range, ignoring: %s", rvalue);
return 0;
}
@@ -883,7 +883,7 @@ int config_parse_tmpfs_size(
r = parse_size(rvalue, 1024, &k);
if (r < 0 || (uint64_t) (size_t) k != k) {
- log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c
index 9a9fb7622d..f38f06baf9 100644
--- a/src/login/sysfs-show.c
+++ b/src/login/sysfs-show.c
@@ -114,7 +114,7 @@ static int show_sysfs_one(
"%s%s:%s%s%s%s",
is_master ? "[MASTER] " : "",
subsystem, sysname,
- name ? " \"" : "", name ? name : "", name ? "\"" : "") < 0)
+ name ? " \"" : "", strempty(name), name ? "\"" : "") < 0)
return -ENOMEM;
free(k);
diff --git a/src/login/systemd-user b/src/login/systemd-user.m4
index 8112d74640..7933508f2b 100644
--- a/src/login/systemd-user
+++ b/src/login/systemd-user.m4
@@ -3,4 +3,9 @@
# Used by systemd --user instances.
account include system-auth
+
+m4_ifdef(`HAVE_SELINUX',
+session required pam_selinux.so close
+session required pam_selinux.so nottys open
+)m4_dnl
session include system-auth
diff --git a/src/machine-id-commit/Makefile b/src/machine-id-commit/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/machine-id-commit/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/machine-id-commit/machine-id-commit.c b/src/machine-id-commit/machine-id-commit.c
deleted file mode 100644
index 0f7748e453..0000000000
--- a/src/machine-id-commit/machine-id-commit.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Didier Roche
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <errno.h>
-
-#include "machine-id-setup.h"
-#include "log.h"
-#include "build.h"
-
-static const char *arg_root = NULL;
-
-static void help(void) {
- printf("%s [OPTIONS...]\n\n"
- "Commit a transient /etc/machine-id on disk if writable.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --root=ROOT Filesystem root\n",
- program_invocation_short_name);
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
- enum {
- ARG_VERSION = 0x100,
- ARG_ROOT,
- };
-
- static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "root", required_argument, NULL, ARG_ROOT },
- {}
- };
-
- int c;
-
- assert(argc >= 0);
- assert(argv);
-
- while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0)
- switch (c) {
-
- case 'h':
- help();
- return 0;
-
- case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
-
- case ARG_ROOT:
- arg_root = optarg;
- break;
-
- case '?':
- return -EINVAL;
-
- default:
- assert_not_reached("Unhandled option");
- }
-
- if (optind < argc) {
- log_error("Extraneous arguments");
- return -EINVAL;
- }
-
- return 1;
-}
-
-int main(int argc, char *argv[]) {
- int r;
-
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
-
- r = parse_argv(argc, argv);
- if (r <= 0)
- goto finish;
-
- r = machine_id_commit(arg_root);
-
-finish:
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c
index 20cb60b804..a9c4e3fadf 100644
--- a/src/machine-id-setup/machine-id-setup-main.c
+++ b/src/machine-id-setup/machine-id-setup-main.c
@@ -19,24 +19,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdio.h>
-#include <getopt.h>
#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
-#include "machine-id-setup.h"
#include "log.h"
-#include "build.h"
+#include "machine-id-setup.h"
+#include "util.h"
-static const char *arg_root = "";
+static const char *arg_root = NULL;
+static bool arg_commit = false;
static void help(void) {
printf("%s [OPTIONS...]\n\n"
"Initialize /etc/machine-id from a random source.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
- " --root=ROOT Filesystem root\n",
- program_invocation_short_name);
+ " --root=ROOT Filesystem root\n"
+ " --commit Commit transient ID\n"
+ , program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
@@ -44,12 +46,14 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_ROOT,
+ ARG_COMMIT,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "root", required_argument, NULL, ARG_ROOT },
+ { "commit", no_argument, NULL, ARG_COMMIT },
{}
};
@@ -67,14 +71,16 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ROOT:
arg_root = optarg;
break;
+ case ARG_COMMIT:
+ arg_commit = true;
+ break;
+
case '?':
return -EINVAL;
@@ -100,5 +106,11 @@ int main(int argc, char *argv[]) {
if (r <= 0)
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
- return machine_id_setup(arg_root) < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+ if (arg_commit)
+ r = machine_id_commit(arg_root);
+ else
+ r = machine_id_setup(arg_root);
+
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c
index 6aaaa8aa31..6e41e92962 100644
--- a/src/machine/machine-dbus.c
+++ b/src/machine/machine-dbus.c
@@ -353,9 +353,9 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
r = wait_for_terminate(child, &si);
if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
+ return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
break;
}
@@ -444,9 +444,9 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
r = wait_for_terminate(child, &si);
if (r < 0)
- return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
+ return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
- return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
break;
}
@@ -639,7 +639,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
_cleanup_free_ char *pty_name = NULL;
_cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL;
sd_bus *container_bus = NULL;
- _cleanup_close_ int master = -1;
+ _cleanup_close_ int master = -1, slave = -1;
_cleanup_strv_free_ char **env = NULL, **args = NULL;
Machine *m = userdata;
const char *p, *unit, *user, *path, *description, *utmp_id;
@@ -700,8 +700,11 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
return r;
p = path_startswith(pty_name, "/dev/pts/");
- if (!p)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
+ assert(p);
+
+ slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (slave < 0)
+ return slave;
utmp_id = path_startswith(pty_name, "/dev/");
assert(utmp_id);
@@ -735,20 +738,19 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
description = strjoina("Shell for User ", isempty(user) ? "root" : user);
r = sd_bus_message_append(tm,
- "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
+ "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
"Description", "s", description,
- "StandardInput", "s", "tty",
- "StandardOutput", "s", "tty",
- "StandardError", "s", "tty",
- "TTYPath", "s", pty_name,
+ "StandardInputFileDescriptor", "h", slave,
+ "StandardOutputFileDescriptor", "h", slave,
+ "StandardErrorFileDescriptor", "h", slave,
"SendSIGHUP", "b", true,
"IgnoreSIGPIPE", "b", false,
"KillMode", "s", "mixed",
- "TTYVHangup", "b", true,
"TTYReset", "b", true,
"UtmpIdentifier", "s", utmp_id,
"UtmpMode", "s", "user",
- "PAMName", "s", "login");
+ "PAMName", "s", "login",
+ "WorkingDirectory", "s", "-~");
if (r < 0)
return r;
@@ -844,6 +846,8 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
if (r < 0)
return r;
+ slave = safe_close(slave);
+
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;
@@ -1040,11 +1044,11 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
r = wait_for_terminate(child, &si);
if (r < 0) {
- r = sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
+ r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
goto finish;
}
if (si.si_code != CLD_EXITED) {
- r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
goto finish;
}
if (si.si_status != EXIT_SUCCESS) {
@@ -1052,7 +1056,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
else
- r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client failed.");
+ r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed.");
goto finish;
}
@@ -1088,7 +1092,7 @@ static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void
o->pid = 0;
if (si->si_code != CLD_EXITED) {
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
goto fail;
}
@@ -1096,7 +1100,7 @@ static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void
if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
r = sd_bus_error_set_errnof(&error, r, "%m");
else
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client failed.");
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
goto fail;
}
diff --git a/src/machine/machine-dbus.h b/src/machine/machine-dbus.h
index 38b46ad936..194e680e05 100644
--- a/src/machine/machine-dbus.h
+++ b/src/machine/machine-dbus.h
@@ -23,6 +23,8 @@
#include "sd-bus.h"
+#include "machine.h"
+
extern const sd_bus_vtable machine_vtable[];
char *machine_bus_path(Machine *s);
diff --git a/src/machine/machine.c b/src/machine/machine.c
index b52ecd015c..7ab84607fb 100644
--- a/src/machine/machine.c
+++ b/src/machine/machine.c
@@ -19,23 +19,24 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <errno.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
#include "sd-messages.h"
-#include "util.h"
-#include "mkdir.h"
-#include "hashmap.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "fileio.h"
+#include "formats-util.h"
+#include "hashmap.h"
+#include "mkdir.h"
#include "special.h"
+#include "terminal-util.h"
#include "unit-name.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "machine.h"
+#include "util.h"
#include "machine-dbus.h"
-#include "formats-util.h"
+#include "machine.h"
Machine* machine_new(Manager *manager, MachineClass class, const char *name) {
Machine *m;
@@ -571,6 +572,25 @@ int machine_openpt(Machine *m, int flags) {
}
}
+int machine_open_terminal(Machine *m, const char *path, int mode) {
+ assert(m);
+
+ switch (m->class) {
+
+ case MACHINE_HOST:
+ return open_terminal(path, mode);
+
+ case MACHINE_CONTAINER:
+ if (m->leader <= 0)
+ return -EINVAL;
+
+ return open_terminal_in_namespace(m->leader, path, mode);
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
MachineOperation *machine_operation_unref(MachineOperation *o) {
if (!o)
return NULL;
diff --git a/src/machine/machine.h b/src/machine/machine.h
index 5f978289f2..ad7f2a162f 100644
--- a/src/machine/machine.h
+++ b/src/machine/machine.h
@@ -123,3 +123,4 @@ const char *kill_who_to_string(KillWho k) _const_;
KillWho kill_who_from_string(const char *s) _pure_;
int machine_openpt(Machine *m, int flags);
+int machine_open_terminal(Machine *m, const char *path, int mode);
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index ab113efb28..0a21ab4415 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -19,44 +19,44 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/socket.h>
-#include <unistd.h>
+#include <arpa/inet.h>
#include <errno.h>
-#include <string.h>
+#include <fcntl.h>
#include <getopt.h>
#include <locale.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
#include <net/if.h>
+#include <netinet/in.h>
+#include <string.h>
#include <sys/mount.h>
+#include <sys/socket.h>
+#include <unistd.h>
#include "sd-bus.h"
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "pager.h"
-#include "spawn-polkit-agent.h"
-#include "bus-util.h"
+
#include "bus-error.h"
-#include "build.h"
-#include "strv.h"
-#include "unit-name.h"
+#include "bus-util.h"
#include "cgroup-show.h"
-#include "logs-show.h"
#include "cgroup-util.h"
-#include "ptyfwd.h"
-#include "event-util.h"
-#include "path-util.h"
-#include "mkdir.h"
#include "copy.h"
-#include "verbs.h"
+#include "env-util.h"
+#include "event-util.h"
+#include "hostname-util.h"
#include "import-util.h"
+#include "log.h"
+#include "logs-show.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "pager.h"
+#include "path-util.h"
#include "process-util.h"
-#include "terminal-util.h"
+#include "ptyfwd.h"
#include "signal-util.h"
-#include "env-util.h"
-#include "hostname-util.h"
+#include "spawn-polkit-agent.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "unit-name.h"
+#include "util.h"
+#include "verbs.h"
static char **arg_property = NULL;
static bool arg_all = false;
@@ -327,7 +327,7 @@ static int list_images(int argc, char *argv[], void *userdata) {
printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
(int) max_name, images[j].name,
(int) max_type, images[j].type,
- images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
+ images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_normal() : "",
(int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
(int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
(int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
@@ -793,7 +793,7 @@ static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
printf("\t RO: %s%s%s\n",
i->read_only ? ansi_highlight_red() : "",
i->read_only ? "read-only" : "writable",
- i->read_only ? ansi_highlight_off() : "");
+ i->read_only ? ansi_normal() : "");
s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
@@ -1173,7 +1173,7 @@ static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *r
return 0;
}
-static int process_forward(sd_event *event, PTYForward **forward, int master, bool ignore_vhangup, const char *name) {
+static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) {
char last_char = 0;
bool machine_died;
int ret = 0, r;
@@ -1192,7 +1192,7 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, bo
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
- r = pty_forward_new(event, master, ignore_vhangup, false, forward);
+ r = pty_forward_new(event, master, flags, forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");
@@ -1203,7 +1203,7 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, bo
pty_forward_get_last_char(*forward, &last_char);
machine_died =
- ignore_vhangup &&
+ (flags & PTY_FORWARD_IGNORE_VHANGUP) &&
pty_forward_get_ignore_vhangup(*forward) == 0;
*forward = pty_forward_free(*forward);
@@ -1286,7 +1286,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
- return process_forward(event, &forward, master, true, machine);
+ return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_VHANGUP, machine);
}
static int shell_machine(int argc, char *argv[], void *userdata) {
@@ -1390,7 +1390,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
- return process_forward(event, &forward, master, false, machine);
+ return process_forward(event, &forward, master, 0, machine);
}
static int remove_image(int argc, char *argv[], void *userdata) {
@@ -2554,9 +2554,7 @@ static int parse_argv(int argc, char *argv[]) {
return help(0, NULL, NULL);
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'p':
r = strv_extend(&arg_property, optarg);
@@ -2747,7 +2745,7 @@ int main(int argc, char*argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index eef9c5fa5f..41bb106d28 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -876,7 +876,7 @@ static int method_map_from_machine_user(sd_bus_message *message, void *userdata,
if (r < 0)
return r;
- if (UID_IS_INVALID(uid))
+ if (!uid_is_valid(uid))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
machine = hashmap_get(m->machines, name);
@@ -910,7 +910,7 @@ static int method_map_from_machine_user(sd_bus_message *message, void *userdata,
continue;
converted = uid - uid_base + uid_shift;
- if (UID_IS_INVALID(converted))
+ if (!uid_is_valid(converted))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
@@ -929,7 +929,7 @@ static int method_map_to_machine_user(sd_bus_message *message, void *userdata, s
r = sd_bus_message_read(message, "u", &uid);
if (r < 0)
return r;
- if (UID_IS_INVALID(uid))
+ if (!uid_is_valid(uid))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
if (uid < 0x10000)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
@@ -968,7 +968,7 @@ static int method_map_to_machine_user(sd_bus_message *message, void *userdata, s
continue;
converted = (uid - uid_shift + uid_base);
- if (UID_IS_INVALID(converted))
+ if (!uid_is_valid(converted))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
o = machine_bus_path(machine);
@@ -994,7 +994,7 @@ static int method_map_from_machine_group(sd_bus_message *message, void *groupdat
if (r < 0)
return r;
- if (GID_IS_INVALID(gid))
+ if (!gid_is_valid(gid))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
machine = hashmap_get(m->machines, name);
@@ -1028,7 +1028,7 @@ static int method_map_from_machine_group(sd_bus_message *message, void *groupdat
continue;
converted = gid - gid_base + gid_shift;
- if (GID_IS_INVALID(converted))
+ if (!gid_is_valid(converted))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
@@ -1047,7 +1047,7 @@ static int method_map_to_machine_group(sd_bus_message *message, void *groupdata,
r = sd_bus_message_read(message, "u", &gid);
if (r < 0)
return r;
- if (GID_IS_INVALID(gid))
+ if (!gid_is_valid(gid))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
if (gid < 0x10000)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
@@ -1086,7 +1086,7 @@ static int method_map_to_machine_group(sd_bus_message *message, void *groupdata,
continue;
converted = (gid - gid_shift + gid_base);
- if (GID_IS_INVALID(converted))
+ if (!gid_is_valid(converted))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
o = machine_bus_path(machine);
diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c
index 5bbe314ba0..b0a3add3e7 100644
--- a/src/modules-load/modules-load.c
+++ b/src/modules-load/modules-load.c
@@ -20,17 +20,16 @@
***/
#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
#include <string.h>
#include <sys/stat.h>
-#include <limits.h>
-#include <getopt.h>
#include <libkmod.h>
+#include "conf-files.h"
#include "log.h"
-#include "util.h"
#include "strv.h"
-#include "conf-files.h"
-#include "build.h"
+#include "util.h"
static char **arg_proc_cmdline_modules = NULL;
@@ -51,7 +50,7 @@ static int add_modules(const char *p) {
if (!k)
return log_oom();
- if (strv_extend_strv(&arg_proc_cmdline_modules, k) < 0)
+ if (strv_extend_strv(&arg_proc_cmdline_modules, k, true) < 0)
return log_oom();
return 0;
@@ -199,9 +198,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case '?':
return -EINVAL;
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 786579def0..c78b9444b6 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -19,29 +19,28 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
#include <getopt.h>
#include <net/if.h>
+#include <stdbool.h>
-#include "sd-network.h"
-#include "sd-netlink.h"
-#include "sd-hwdb.h"
#include "sd-device.h"
+#include "sd-hwdb.h"
+#include "sd-netlink.h"
+#include "sd-network.h"
-#include "strv.h"
-#include "build.h"
-#include "util.h"
-#include "pager.h"
-#include "lldp.h"
-#include "netlink-util.h"
+#include "arphrd-list.h"
#include "device-util.h"
+#include "ether-addr-util.h"
#include "hwdb-util.h"
-#include "arphrd-list.h"
+#include "lldp.h"
#include "local-addresses.h"
+#include "netlink-util.h"
+#include "pager.h"
#include "socket-util.h"
-#include "ether-addr-util.h"
-#include "verbs.h"
+#include "strv.h"
#include "terminal-util.h"
+#include "util.h"
+#include "verbs.h"
static bool arg_no_pager = false;
static bool arg_legend = true;
@@ -166,10 +165,10 @@ static void operational_state_to_color(const char *state, const char **on, const
if (streq_ptr(state, "routable")) {
*on = ansi_highlight_green();
- *off = ansi_highlight_off();
+ *off = ansi_normal();
} else if (streq_ptr(state, "degraded")) {
*on = ansi_highlight_yellow();
- *off = ansi_highlight_off();
+ *off = ansi_normal();
} else
*on = *off = "";
}
@@ -180,13 +179,13 @@ static void setup_state_to_color(const char *state, const char **on, const char
if (streq_ptr(state, "configured")) {
*on = ansi_highlight_green();
- *off = ansi_highlight_off();
+ *off = ansi_normal();
} else if (streq_ptr(state, "configuring")) {
*on = ansi_highlight_yellow();
- *off = ansi_highlight_off();
+ *off = ansi_normal();
} else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
*on = ansi_highlight_red();
- *off = ansi_highlight_off();
+ *off = ansi_normal();
} else
*on = *off = "";
}
@@ -1063,9 +1062,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_NO_PAGER:
arg_no_pager = true;
diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c
index d609daafde..b3450c1456 100644
--- a/src/network/networkd-address-pool.c
+++ b/src/network/networkd-address-pool.c
@@ -21,6 +21,7 @@
#include "networkd.h"
#include "networkd-address-pool.h"
+#include "set.h"
int address_pool_new(
Manager *m,
@@ -96,9 +97,10 @@ static bool address_pool_prefix_is_taken(
HASHMAP_FOREACH(l, p->manager->links, i) {
Address *a;
+ Iterator j;
/* Don't clash with assigned addresses */
- LIST_FOREACH(addresses, a, l->addresses) {
+ SET_FOREACH(a, l->addresses, j) {
if (a->family != p->family)
continue;
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index b0d296941e..316ae2e4cb 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -21,26 +21,37 @@
#include <net/if.h>
-#include "utf8.h"
-#include "util.h"
#include "conf-parser.h"
#include "firewall-util.h"
#include "netlink-util.h"
+#include "set.h"
+#include "utf8.h"
+#include "util.h"
#include "networkd.h"
#include "networkd-address.h"
-static void address_init(Address *address) {
- assert(address);
+int address_new(Address **ret) {
+ _cleanup_address_free_ Address *address = NULL;
+
+ address = new0(Address, 1);
+ if (!address)
+ return -ENOMEM;
address->family = AF_UNSPEC;
address->scope = RT_SCOPE_UNIVERSE;
address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
+
+ *ret = address;
+ address = NULL;
+
+ return 0;
}
int address_new_static(Network *network, unsigned section, Address **ret) {
_cleanup_address_free_ Address *address = NULL;
+ int r;
if (section) {
address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
@@ -52,11 +63,9 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
}
}
- address = new0(Address, 1);
- if (!address)
- return -ENOMEM;
-
- address_init(address);
+ r = address_new(&address);
+ if (r < 0)
+ return r;
address->network = network;
@@ -74,21 +83,6 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
return 0;
}
-int address_new_dynamic(Address **ret) {
- _cleanup_address_free_ Address *address = NULL;
-
- address = new0(Address, 1);
- if (!address)
- return -ENOMEM;
-
- address_init(address);
-
- *ret = address;
- address = NULL;
-
- return 0;
-}
-
void address_free(Address *address) {
if (!address)
return;
@@ -101,10 +95,110 @@ void address_free(Address *address) {
UINT_TO_PTR(address->section));
}
+ if (address->link)
+ set_remove(address->link->addresses, address);
+
free(address);
}
-int address_establish(Address *address, Link *link) {
+static void address_hash_func(const void *b, struct siphash *state) {
+ const Address *a = b;
+
+ assert(a);
+
+ siphash24_compress(&a->family, sizeof(a->family), state);
+
+ switch (a->family) {
+ case AF_INET:
+ siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
+
+ /* peer prefix */
+ if (a->prefixlen != 0) {
+ uint32_t prefix;
+
+ if (a->in_addr_peer.in.s_addr != 0)
+ prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
+ else
+ prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
+
+ siphash24_compress(&prefix, sizeof(prefix), state);
+ }
+
+ /* fallthrough */
+ case AF_INET6:
+ /* local address */
+ siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
+
+ break;
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ break;
+ }
+}
+
+static int address_compare_func(const void *c1, const void *c2) {
+ const Address *a1 = c1, *a2 = c2;
+
+ if (a1->family < a2->family)
+ return -1;
+ if (a1->family > a2->family)
+ return 1;
+
+ switch (a1->family) {
+ /* use the same notion of equality as the kernel does */
+ case AF_INET:
+ if (a1->prefixlen < a2->prefixlen)
+ return -1;
+ if (a1->prefixlen > a2->prefixlen)
+ return 1;
+
+ /* compare the peer prefixes */
+ if (a1->prefixlen != 0) {
+ /* make sure we don't try to shift by 32.
+ * See ISO/IEC 9899:TC3 § 6.5.7.3. */
+ uint32_t b1, b2;
+
+ if (a1->in_addr_peer.in.s_addr != 0)
+ b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
+ else
+ b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen);
+
+ if (a2->in_addr_peer.in.s_addr != 0)
+ b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen);
+ else
+ b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen);
+
+ if (b1 < b2)
+ return -1;
+ if (b1 > b2)
+ return 1;
+ }
+
+ /* fall-through */
+ case AF_INET6:
+ return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
+ default:
+ /* treat any other address family as AF_UNSPEC */
+ return 0;
+ }
+}
+
+static const struct hash_ops address_hash_ops = {
+ .hash = address_hash_func,
+ .compare = address_compare_func
+};
+
+bool address_equal(Address *a1, Address *a2) {
+ if (a1 == a2)
+ return true;
+
+ if (!a1 || !a2)
+ return false;
+
+ return address_compare_func(a1, a2) == 0;
+}
+
+static int address_establish(Address *address, Link *link) {
bool masq;
int r;
@@ -131,7 +225,43 @@ int address_establish(Address *address, Link *link) {
return 0;
}
-int address_release(Address *address, Link *link) {
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+ _cleanup_address_free_ Address *address = NULL;
+ int r;
+
+ assert(link);
+ assert(in_addr);
+ assert(ret);
+
+ r = address_new(&address);
+ if (r < 0)
+ return r;
+
+ address->family = family;
+ address->in_addr = *in_addr;
+ address->prefixlen = prefixlen;
+
+ r = set_ensure_allocated(&link->addresses, &address_hash_ops);
+ if (r < 0)
+ return r;
+
+ r = set_put(link->addresses, address);
+ if (r < 0)
+ return r;
+
+ address->link = link;
+
+ r = address_establish(address, link);
+ if (r < 0)
+ return r;
+
+ *ret = address;
+ address = NULL;
+
+ return 0;
+}
+
+static int address_release(Address *address, Link *link) {
int r;
assert(address);
@@ -152,7 +282,36 @@ int address_release(Address *address, Link *link) {
return 0;
}
-int address_drop(Address *address, Link *link,
+int address_drop(Address *address) {
+ assert(address);
+
+ address_release(address, address->link);
+ address_free(address);
+
+ return 0;
+}
+
+int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+ Address address = {}, *existing;
+
+ assert(link);
+ assert(in_addr);
+ assert(ret);
+
+ address.family = family;
+ address.in_addr = *in_addr;
+ address.prefixlen = prefixlen;
+
+ existing = set_get(link->addresses, &address);
+ if (!existing)
+ return -ENOENT;
+
+ *ret = existing;
+
+ return 0;
+}
+
+int address_remove(Address *address, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
int r;
@@ -292,7 +451,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
} else if (original->family == AF_INET6)
in_addr.in6.s6_addr[15] |= 1;
- r = address_new_dynamic(&na);
+ r = address_new(&na);
if (r < 0)
return r;
@@ -430,15 +589,13 @@ int config_parse_broadcast(
return r;
if (n->family == AF_INET6) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
return 0;
}
r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Broadcast is invalid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
return 0;
}
@@ -487,10 +644,10 @@ int config_parse_address(const char *unit,
e = strchr(rvalue, '/');
if (e) {
unsigned i;
+
r = safe_atou(e + 1, &i);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Prefix length is invalid, ignoring assignment: %s", e + 1);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1);
return 0;
}
@@ -502,23 +659,20 @@ int config_parse_address(const char *unit,
r = in_addr_from_string_auto(address, &f, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Address is invalid, ignoring assignment: %s", address);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address);
return 0;
}
if (!e && f == AF_INET) {
r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
return 0;
}
}
if (n->family != AF_UNSPEC && f != n->family) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Address is incompatible, ignoring assignment: %s", address);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address);
return 0;
}
@@ -567,9 +721,7 @@ int config_parse_label(const char *unit,
return log_oom();
if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Interface label is not ASCII clean or is too"
- " long, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
free(label);
return 0;
}
@@ -587,49 +739,8 @@ int config_parse_label(const char *unit,
return 0;
}
-bool address_equal(Address *a1, Address *a2) {
- /* same object */
- if (a1 == a2)
- return true;
-
- /* one, but not both, is NULL */
- if (!a1 || !a2)
- return false;
-
- if (a1->family != a2->family)
- return false;
+bool address_is_ready(const Address *a) {
+ assert(a);
- switch (a1->family) {
- /* use the same notion of equality as the kernel does */
- case AF_UNSPEC:
- return true;
-
- case AF_INET:
- if (a1->prefixlen != a2->prefixlen)
- return false;
- else if (a1->prefixlen == 0)
- /* make sure we don't try to shift by 32.
- * See ISO/IEC 9899:TC3 § 6.5.7.3. */
- return true;
- else {
- uint32_t b1, b2;
-
- b1 = be32toh(a1->in_addr.in.s_addr);
- b2 = be32toh(a2->in_addr.in.s_addr);
-
- return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
- }
-
- case AF_INET6: {
- uint64_t *b1, *b2;
-
- b1 = (uint64_t*)&a1->in_addr.in6;
- b2 = (uint64_t*)&a2->in_addr.in6;
-
- return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
- }
-
- default:
- assert_not_reached("Invalid address family");
- }
+ return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
}
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 39789a2382..425344fe48 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -38,6 +38,8 @@ struct Address {
Network *network;
unsigned section;
+ Link *link;
+
int family;
unsigned char prefixlen;
unsigned char scope;
@@ -56,14 +58,16 @@ struct Address {
};
int address_new_static(Network *network, unsigned section, Address **ret);
-int address_new_dynamic(Address **ret);
+int address_new(Address **ret);
void address_free(Address *address);
+int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_drop(Address *address);
int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback);
int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback);
-int address_establish(Address *address, Link *link);
-int address_release(Address *address, Link *link);
+int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback);
bool address_equal(Address *a1, Address *a2);
+bool address_is_ready(const Address *a);
DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
#define _cleanup_address_free_ _cleanup_(address_freep)
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 4ffb01382f..5d9bfcea7c 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -72,11 +72,11 @@ static int link_set_dhcp_routes(Link *link) {
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
- r = route_new_dynamic(&route, RTPROT_DHCP);
+ r = route_new(&route, RTPROT_DHCP);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
- r = route_new_dynamic(&route_gw, RTPROT_DHCP);
+ r = route_new(&route_gw, RTPROT_DHCP);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
@@ -120,7 +120,7 @@ static int link_set_dhcp_routes(Link *link) {
for (i = 0; i < n; i++) {
_cleanup_route_free_ Route *route = NULL;
- r = route_new_dynamic(&route, RTPROT_DHCP);
+ r = route_new(&route, RTPROT_DHCP);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate route: %m");
@@ -162,45 +162,45 @@ static int dhcp_lease_lost(Link *link) {
for (i = 0; i < n; i++) {
_cleanup_route_free_ Route *route = NULL;
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
+ r = route_new(&route, RTPROT_UNSPEC);
if (r >= 0) {
route->family = AF_INET;
route->in_addr.in = routes[i].gw_addr;
route->dst_addr.in = routes[i].dst_addr;
route->dst_prefixlen = routes[i].dst_prefixlen;
- route_drop(route, link,
- &link_route_drop_handler);
+ route_remove(route, link,
+ &link_route_remove_handler);
}
}
}
}
- r = address_new_dynamic(&address);
+ r = address_new(&address);
if (r >= 0) {
r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
if (r >= 0) {
_cleanup_route_free_ Route *route_gw = NULL;
_cleanup_route_free_ Route *route = NULL;
- r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
+ r = route_new(&route_gw, RTPROT_UNSPEC);
if (r >= 0) {
route_gw->family = AF_INET;
route_gw->dst_addr.in = gateway;
route_gw->dst_prefixlen = 32;
route_gw->scope = RT_SCOPE_LINK;
- route_drop(route_gw, link,
- &link_route_drop_handler);
+ route_remove(route_gw, link,
+ &link_route_remove_handler);
}
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
+ r = route_new(&route, RTPROT_UNSPEC);
if (r >= 0) {
route->family = AF_INET;
route->in_addr.in = gateway;
- route_drop(route, link,
- &link_route_drop_handler);
+ route_remove(route, link,
+ &link_route_remove_handler);
}
}
@@ -214,7 +214,7 @@ static int dhcp_lease_lost(Link *link) {
address->in_addr.in = addr;
address->prefixlen = prefixlen;
- address_drop(address, link, &link_address_drop_handler);
+ address_remove(address, link, &link_address_remove_handler);
}
}
@@ -267,7 +267,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
link_enter_failed(link);
} else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
link_set_dhcp_routes(link);
@@ -288,7 +288,7 @@ static int dhcp4_update_address(Link *link,
prefixlen = in_addr_netmask_to_prefixlen(netmask);
- r = address_new_dynamic(&addr);
+ r = address_new(&addr);
if (r < 0)
return r;
@@ -471,9 +471,9 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
return;
switch (event) {
- case DHCP_EVENT_EXPIRED:
- case DHCP_EVENT_STOP:
- case DHCP_EVENT_IP_CHANGE:
+ case SD_DHCP_CLIENT_EVENT_EXPIRED:
+ case SD_DHCP_CLIENT_EVENT_STOP:
+ case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
if (link->network->dhcp_critical) {
log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
return;
@@ -487,7 +487,7 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
}
}
- if (event == DHCP_EVENT_IP_CHANGE) {
+ if (event == SD_DHCP_CLIENT_EVENT_IP_CHANGE) {
r = dhcp_lease_acquired(client, link);
if (r < 0) {
link_enter_failed(link);
@@ -496,14 +496,14 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
}
break;
- case DHCP_EVENT_RENEW:
+ case SD_DHCP_CLIENT_EVENT_RENEW:
r = dhcp_lease_renew(client, link);
if (r < 0) {
link_enter_failed(link);
return;
}
break;
- case DHCP_EVENT_IP_ACQUIRE:
+ case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
r = dhcp_lease_acquired(client, link);
if (r < 0) {
link_enter_failed(link);
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index 3a5ac1c39b..2f9ecf7a89 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -53,13 +53,12 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
return 1;
}
- log_link_error(link, "Could not set DHCPv6 address: %s",
- strerror(-r));
+ log_link_error_errno(link, r, "Could not set DHCPv6 address: %m");
link_enter_failed(link);
} else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
return 1;
}
@@ -70,7 +69,7 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
int r;
_cleanup_address_free_ Address *addr = NULL;
- r = address_new_dynamic(&addr);
+ r = address_new(&addr);
if (r < 0)
return r;
@@ -84,8 +83,8 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
addr->cinfo.ifa_valid = lifetime_valid;
log_link_info(link,
- "DHCPv6 address "SD_ICMP6_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
- SD_ICMP6_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
+ "DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d",
+ SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6),
addr->prefixlen, lifetime_preferred, lifetime_valid);
r = address_update(addr, link, dhcp6_address_handler);
@@ -115,8 +114,7 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery,
&ip6_addr, &prefixlen);
if (r < 0 && r != -EADDRNOTAVAIL) {
- log_link_warning(link, "Could not get prefix information: %s",
- strerror(-r));
+ log_link_warning_errno(link, r, "Could not get prefix information: %m");
return r;
}
@@ -144,13 +142,15 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
return;
switch(event) {
- case DHCP6_EVENT_STOP:
- case DHCP6_EVENT_RESEND_EXPIRE:
- case DHCP6_EVENT_RETRANS_MAX:
- log_link_debug(link, "DHCPv6 event %d", event);
+ case SD_DHCP6_CLIENT_EVENT_STOP:
+ case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE:
+ case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX:
+ log_link_warning(link, "DHCPv6 lease lost");
+
+ link->dhcp6_configured = false;
break;
- case DHCP6_EVENT_IP_ACQUIRE:
+ case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE:
r = dhcp6_lease_address_acquired(client, link);
if (r < 0) {
link_enter_failed(link);
@@ -158,24 +158,25 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
}
/* fall through */
- case DHCP6_EVENT_INFORMATION_REQUEST:
+ case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST:
r = dhcp6_lease_information_acquired(client, link);
if (r < 0) {
link_enter_failed(link);
return;
}
+ link->dhcp6_configured = true;
break;
default:
if (event < 0)
- log_link_warning(link, "DHCPv6 error: %s",
- strerror(-event));
+ log_link_warning_errno(link, event, "DHCPv6 error: %m");
else
- log_link_warning(link, "DHCPv6 unknown event: %d",
- event);
+ log_link_warning(link, "DHCPv6 unknown event: %d", event);
return;
}
+
+ link_client_handler(link);
}
static int dhcp6_configure(Link *link, int event) {
@@ -183,91 +184,86 @@ static int dhcp6_configure(Link *link, int event) {
bool information_request;
assert_return(link, -EINVAL);
+ assert_return(IN_SET(event, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT,
+ SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER,
+ SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED), -EINVAL);
- if (link->dhcp6_client) {
- if (event != ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED)
- return 0;
+ link->dhcp6_configured = false;
+ if (link->dhcp6_client) {
r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
&information_request);
if (r < 0) {
- log_link_warning(link, "Could not get DHCPv6 Information request setting: %s",
- strerror(-r));
- link->dhcp6_client =
- sd_dhcp6_client_unref(link->dhcp6_client);
- return r;
+ log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m");
+ goto error;
}
- if (!information_request)
- return r;
+ if (information_request && event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
+ r = sd_dhcp6_client_stop(link->dhcp6_client);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m");
+ goto error;
+ }
+
+ r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
+ false);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m");
+ goto error;
+ }
- r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
- false);
- if (r < 0) {
- log_link_warning(link, "Could not unset DHCPv6 Information request: %s",
- strerror(-r));
- link->dhcp6_client =
- sd_dhcp6_client_unref(link->dhcp6_client);
- return r;
}
r = sd_dhcp6_client_start(link->dhcp6_client);
- if (r < 0) {
- log_link_warning(link, "Could not restart DHCPv6 after enabling Information request: %s",
- strerror(-r));
- link->dhcp6_client =
- sd_dhcp6_client_unref(link->dhcp6_client);
- return r;
+ if (r < 0 && r != -EALREADY) {
+ log_link_warning_errno(link, r, "Could not restart DHCPv6: %m");
+ goto error;
}
+ if (r == -EALREADY)
+ link->dhcp6_configured = true;
+
return r;
}
r = sd_dhcp6_client_new(&link->dhcp6_client);
if (r < 0)
- return r;
+ goto error;
r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0);
- if (r < 0) {
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
- return r;
- }
+ if (r < 0)
+ goto error;
r = sd_dhcp6_client_set_mac(link->dhcp6_client,
(const uint8_t *) &link->mac,
sizeof (link->mac), ARPHRD_ETHER);
- if (r < 0) {
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
- return r;
- }
+ if (r < 0)
+ goto error;
r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex);
- if (r < 0) {
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
- return r;
- }
+ if (r < 0)
+ goto error;
r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler,
link);
- if (r < 0) {
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
- return r;
- }
+ if (r < 0)
+ goto error;
- if (event == ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER) {
+ if (event == SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) {
r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
true);
- if (r < 0) {
- link->dhcp6_client =
- sd_dhcp6_client_unref(link->dhcp6_client);
- return r;
- }
+ if (r < 0)
+ goto error;
}
r = sd_dhcp6_client_start(link->dhcp6_client);
if (r < 0)
- link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
+ goto error;
+
+ return r;
+ error:
+ link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
return r;
}
@@ -287,8 +283,8 @@ static int dhcp6_prefix_expired(Link *link) {
if (r < 0)
return r;
- log_link_info(link, "IPv6 prefix "SD_ICMP6_ADDRESS_FORMAT_STR"/%d expired",
- SD_ICMP6_ADDRESS_FORMAT_VAL(*expired_prefix),
+ log_link_info(link, "IPv6 prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d expired",
+ SD_ICMP6_ND_ADDRESS_FORMAT_VAL(*expired_prefix),
expired_prefixlen);
sd_dhcp6_lease_reset_address_iter(lease);
@@ -302,7 +298,7 @@ static int dhcp6_prefix_expired(Link *link) {
if (r < 0)
continue;
- log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ADDRESS_FORMAT_VAL(ip6_addr), 128);
+ log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(ip6_addr), 128);
dhcp6_address_update(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid);
}
@@ -321,17 +317,17 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
return;
switch(event) {
- case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE:
+ case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE:
return;
- case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
- case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER:
- case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED:
+ case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
+ case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER:
+ case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED:
dhcp6_configure(link, event);
break;
- case ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
+ case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
if (!link->rtnl_extended_attrs)
dhcp6_prefix_expired(link);
@@ -339,11 +335,9 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
default:
if (event < 0)
- log_link_warning(link, "ICMPv6 error: %s",
- strerror(-event));
+ log_link_warning_errno(link, event, "ICMPv6 error: %m");
else
- log_link_warning(link, "ICMPv6 unknown event: %d",
- event);
+ log_link_warning(link, "ICMPv6 unknown event: %d", event);
break;
}
diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c
index 22efadb843..9cb63cb79f 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -197,7 +197,7 @@ int config_parse_fdb_hwaddr(
&fdb_entry->mac_addr->ether_addr_octet[5]);
if (ETHER_ADDR_LEN != r) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not a valid MAC address, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
return 0;
}
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 0a27a30278..01ee9f9f4a 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -42,9 +42,9 @@ static int ipv4ll_address_lost(Link *link) {
log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr));
- r = address_new_dynamic(&address);
+ r = address_new(&address);
if (r < 0) {
- log_link_error(link, "Could not allocate address: %s", strerror(-r));
+ log_link_error_errno(link, r, "Could not allocate address: %m");
return r;
}
@@ -53,12 +53,11 @@ static int ipv4ll_address_lost(Link *link) {
address->prefixlen = 16;
address->scope = RT_SCOPE_LINK;
- address_drop(address, link, &link_address_drop_handler);
+ address_remove(address, link, &link_address_remove_handler);
- r = route_new_dynamic(&route, RTPROT_UNSPEC);
+ r = route_new(&route, RTPROT_UNSPEC);
if (r < 0) {
- log_link_error(link, "Could not allocate route: %s",
- strerror(-r));
+ log_link_error_errno(link, r, "Could not allocate route: %m");
return r;
}
@@ -66,7 +65,7 @@ static int ipv4ll_address_lost(Link *link) {
route->scope = RT_SCOPE_LINK;
route->metrics = IPV4LL_ROUTE_METRIC;
- route_drop(route, link, &link_route_drop_handler);
+ route_remove(route, link, &link_route_remove_handler);
link_client_handler(link);
@@ -82,7 +81,7 @@ static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_link_error(link, "could not set ipv4ll route: %s", strerror(-r));
+ log_link_error_errno(link, r, "could not set ipv4ll route: %m");
link_enter_failed(link);
}
@@ -103,10 +102,10 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_link_error(link, "could not set ipv4ll address: %s", strerror(-r));
+ log_link_error_errno(link, r, "could not set ipv4ll address: %m");
link_enter_failed(link);
} else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
link->ipv4ll_address = true;
@@ -134,7 +133,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u",
ADDRESS_FMT_VAL(address));
- r = address_new_dynamic(&ll_addr);
+ r = address_new(&ll_addr);
if (r < 0)
return r;
@@ -150,7 +149,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
link->ipv4ll_address = false;
- r = route_new_dynamic(&route, RTPROT_STATIC);
+ r = route_new(&route, RTPROT_STATIC);
if (r < 0)
return r;
@@ -179,15 +178,15 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
return;
switch(event) {
- case IPV4LL_EVENT_STOP:
- case IPV4LL_EVENT_CONFLICT:
+ case SD_IPV4LL_EVENT_STOP:
+ case SD_IPV4LL_EVENT_CONFLICT:
r = ipv4ll_address_lost(link);
if (r < 0) {
link_enter_failed(link);
return;
}
break;
- case IPV4LL_EVENT_BIND:
+ case SD_IPV4LL_EVENT_BIND:
r = ipv4ll_address_claimed(ll, link);
if (r < 0) {
link_enter_failed(link);
@@ -195,10 +194,7 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
}
break;
default:
- if (event < 0)
- log_link_warning(link, "IPv4 link-local error: %s", strerror(-event));
- else
- log_link_warning(link, "IPv4 link-local unknown event: %d", event);
+ log_link_warning(link, "IPv4 link-local unknown event: %d", event);
break;
}
}
@@ -218,7 +214,9 @@ int ipv4ll_configure(Link *link) {
if (link->udev_device) {
r = net_get_unique_predictable_data(link->udev_device, seed);
if (r >= 0) {
- r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
+ assert_cc(sizeof(unsigned) <= 8);
+
+ r = sd_ipv4ll_set_address_seed(link->ipv4ll, *(unsigned *)seed);
if (r < 0)
return r;
}
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 9d4a69b0db..f6cc1f8ee2 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -23,15 +23,16 @@
#include <linux/if.h>
#include <unistd.h>
-#include "util.h"
-#include "virt.h"
-#include "fileio.h"
-#include "socket-util.h"
#include "bus-util.h"
-#include "udev-util.h"
-#include "netlink-util.h"
#include "dhcp-lease-internal.h"
+#include "fileio.h"
+#include "netlink-util.h"
#include "network-internal.h"
+#include "set.h"
+#include "socket-util.h"
+#include "udev-util.h"
+#include "util.h"
+#include "virt.h"
#include "networkd-link.h"
#include "networkd-netdev.h"
@@ -291,10 +292,10 @@ static void link_free(Link *link) {
if (!link)
return;
- while ((address = link->addresses)) {
- LIST_REMOVE(addresses, link->addresses, address);
- address_free(address);
- }
+ while (!set_isempty(link->addresses))
+ address_free(set_first(link->addresses));
+
+ set_free(link->addresses);
while ((address = link->pool_addresses)) {
LIST_REMOVE(addresses, link->pool_addresses, address);
@@ -336,15 +337,28 @@ static void link_free(Link *link) {
}
Link *link_unref(Link *link) {
- if (link && (-- link->n_ref <= 0))
- link_free(link);
+ if (!link)
+ return NULL;
+
+ assert(link->n_ref > 0);
+
+ link->n_ref --;
+
+ if (link->n_ref > 0)
+ return NULL;
+
+ link_free(link);
return NULL;
}
Link *link_ref(Link *link) {
- if (link)
- assert_se(++ link->n_ref >= 2);
+ if (!link)
+ return NULL;
+
+ assert(link->n_ref > 0);
+
+ link->n_ref ++;
return link;
}
@@ -501,8 +515,13 @@ void link_client_handler(Link *link) {
!link->ipv4ll_route)
return;
- if (link_dhcp4_enabled(link) && !link->dhcp4_configured)
- return;
+ if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
+ !link->dhcp4_configured) ||
+ (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
+ !link->dhcp6_configured) ||
+ (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
+ !link->dhcp4_configured && !link->dhcp6_configured))
+ return;
if (link->state != LINK_STATE_CONFIGURED)
link_enter_configured(link);
@@ -526,7 +545,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_link_warning_errno(link, r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not set route: %m");
if (link->link_messages == 0) {
log_link_debug(link, "Routes set");
@@ -567,7 +586,7 @@ static int link_enter_set_routes(Link *link) {
return 0;
}
-int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
@@ -580,7 +599,7 @@ int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -ESRCH)
- log_link_warning_errno(link, r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not drop route: %m");
return 1;
}
@@ -604,9 +623,9 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST)
- log_link_warning_errno(link, r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "could not set address: %m");
else if (r >= 0)
- link_rtnl_process_address(rtnl, m, link->manager);
+ manager_rtnl_process_address(rtnl, m, link->manager);
if (link->link_messages == 0) {
log_link_debug(link, "Addresses set");
@@ -849,7 +868,7 @@ static int link_enter_set_addresses(Link *link) {
return 0;
}
-int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
@@ -862,7 +881,7 @@ int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *use
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EADDRNOTAVAIL)
- log_link_warning_errno(link, r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not drop address: %m");
return 1;
}
@@ -1014,7 +1033,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
r = sd_netlink_message_get_errno(m);
if (r < 0)
- log_link_warning_errno(link, r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not set MTU: %m");
return 1;
}
@@ -1112,13 +1131,16 @@ static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
assert(link->network);
assert(link->manager);
- if (event != UPDATE_INFO)
- return;
-
- r = sd_lldp_save(link->lldp, link->lldp_file);
- if (r < 0)
- log_link_warning_errno(link, r, "Could not save LLDP: %m");
+ switch (event) {
+ case SD_LLDP_EVENT_UPDATE_INFO:
+ r = sd_lldp_save(link->lldp, link->lldp_file);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Could not save LLDP: %m");
+ break;
+ default:
+ break;
+ }
}
static int link_acquire_conf(Link *link) {
@@ -1199,7 +1221,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
if (r < 0)
/* we warn but don't fail the link, as it may be
brought up later */
- log_link_warning_errno(link, r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not bring up interface: %m");
return 1;
}
@@ -1286,7 +1308,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *user
r = sd_netlink_message_get_errno(m);
if (r < 0)
- log_link_warning_errno(link, r, "%-*s: could not bring down interface: %m", IFNAMSIZ, link->ifname);
+ log_link_warning_errno(link, r, "Could not bring down interface: %m");
return 1;
}
@@ -1608,7 +1630,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *us
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
- log_link_error_errno(link, r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname);
+ log_link_error_errno(link, r, "Could not join netdev: %m");
link_enter_failed(link);
return 1;
} else
@@ -1789,6 +1811,45 @@ static int link_set_ipv6_privacy_extensions(Link *link) {
return 0;
}
+static int link_set_ipv6_accept_ra(Link *link) {
+ const char *p = NULL, *v = NULL;
+ int r;
+
+ /* Make this a NOP if IPv6 is not available */
+ if (!socket_ipv6_is_supported())
+ return 0;
+
+ if (link->flags & IFF_LOOPBACK)
+ return 0;
+
+ /* If unset use system default (enabled if local forwarding is disabled.
+ * disabled if local forwarding is enabled).
+ * If set, ignore or enforce RA independent of local forwarding state.
+ */
+ if (link->network->ipv6_accept_ra < 0)
+ /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */
+ v = "1";
+ else if (link->network->ipv6_accept_ra > 0)
+ /* "2" means accept RA even if ip_forward is enabled */
+ v = "2";
+ else
+ /* "0" means ignore RA */
+ v = "0";
+
+ p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra");
+
+ r = write_string_file(p, v, 0);
+ if (r < 0) {
+ /* If the right value is set anyway, don't complain */
+ if (verify_one_line_file(p, v) > 0)
+ return 0;
+
+ log_link_warning_errno(link, r, "Cannot configure IPv6 accept_ra for interface: %m");
+ }
+
+ return 0;
+}
+
static int link_configure(Link *link) {
int r;
@@ -1812,6 +1873,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
+ r = link_set_ipv6_accept_ra(link);
+ if (r < 0)
+ return r;
+
if (link_ipv4ll_enabled(link)) {
r = ipv4ll_configure(link);
if (r < 0)
@@ -1960,179 +2025,6 @@ int link_initialized(Link *link, struct udev_device *device) {
return 0;
}
-static Address* link_get_equal_address(Link *link, Address *needle) {
- Address *i;
-
- assert(link);
- assert(needle);
-
- LIST_FOREACH(addresses, i, link->addresses)
- if (address_equal(i, needle))
- return i;
-
- return NULL;
-}
-
-int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
- Manager *m = userdata;
- Link *link = NULL;
- uint16_t type;
- _cleanup_address_free_ Address *address = NULL;
- unsigned char flags;
- Address *existing;
- char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
- const char *valid_str = NULL;
- int r, ifindex;
-
- assert(rtnl);
- assert(message);
- assert(m);
-
- if (sd_netlink_message_is_error(message)) {
- r = sd_netlink_message_get_errno(message);
- if (r < 0)
- log_warning_errno(r, "rtnl: failed to receive address: %m");
-
- return 0;
- }
-
- r = sd_netlink_message_get_type(message, &type);
- if (r < 0) {
- log_warning_errno(r, "rtnl: could not get message type: %m");
- return 0;
- } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
- log_warning("rtnl: received unexpected message type when processing address");
- return 0;
- }
-
- r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
- if (r < 0) {
- log_warning_errno(r, "rtnl: could not get ifindex from address: %m");
- return 0;
- } else if (ifindex <= 0) {
- log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
- return 0;
- } else {
- r = link_get(m, ifindex, &link);
- if (r < 0 || !link) {
- /* when enumerating we might be out of sync, but we will
- * get the address again, so just ignore it */
- if (!m->enumerating)
- log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
- return 0;
- }
- }
-
- r = address_new_dynamic(&address);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_addr_get_family(message, &address->family);
- if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) {
- log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
- return 0;
- }
-
- r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
- return 0;
- }
-
- r = sd_rtnl_message_addr_get_scope(message, &address->scope);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
- return 0;
- }
-
- r = sd_rtnl_message_addr_get_flags(message, &flags);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
- return 0;
- }
- address->flags = flags;
-
- switch (address->family) {
- case AF_INET:
- r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
- return 0;
- }
-
- break;
-
- case AF_INET6:
- r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6);
- if (r < 0) {
- log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
- return 0;
- }
-
- break;
-
- default:
- assert_not_reached("invalid address family");
- }
-
- if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) {
- log_link_warning(link, "Could not print address");
- return 0;
- }
-
- r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &address->cinfo);
- if (r >= 0) {
- if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
- valid_str = "ever";
- else
- valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
- address->cinfo.ifa_valid * USEC_PER_SEC,
- USEC_PER_SEC);
- }
-
- existing = link_get_equal_address(link, address);
-
- switch (type) {
- case RTM_NEWADDR:
- if (existing) {
- log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
-
-
- existing->scope = address->scope;
- existing->flags = address->flags;
- existing->cinfo = address->cinfo;
-
- } else {
- log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
-
- LIST_PREPEND(addresses, link->addresses, address);
- address_establish(address, link);
-
- address = NULL;
-
- link_save(link);
- }
-
- break;
-
- case RTM_DELADDR:
-
- if (existing) {
- log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
- address_release(existing, link);
- LIST_REMOVE(addresses, link->addresses, existing);
- address_free(existing);
- } else
- log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str);
-
- break;
- default:
- assert_not_reached("Received invalid RTNL message type");
- }
-
- return 1;
-}
-
int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
Link *link;
_cleanup_udev_device_unref_ struct udev_device *device = NULL;
@@ -2156,8 +2048,10 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
/* not in a container, udev will be around */
sprintf(ifindex_str, "n%d", link->ifindex);
device = udev_device_new_from_device_id(m->udev, ifindex_str);
- if (!device)
- return log_link_warning_errno(link, errno, "Could not find udev device: %m");
+ if (!device) {
+ r = log_link_warning_errno(link, errno, "Could not find udev device: %m");
+ goto failed;
+ }
if (udev_device_get_is_initialized(device) <= 0) {
/* not yet ready */
@@ -2167,17 +2061,20 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
r = link_initialized(link, device);
if (r < 0)
- return r;
+ goto failed;
} else {
/* we are calling a callback directly, so must take a ref */
link_ref(link);
r = link_initialized_and_synced(m->rtnl, NULL, link);
if (r < 0)
- return r;
+ goto failed;
}
return 0;
+failed:
+ link_enter_failed(link);
+ return r;
}
static int link_carrier_gained(Link *link) {
@@ -2374,10 +2271,11 @@ static void link_update_operstate(Link *link) {
else if (link_has_carrier(link)) {
Address *address;
uint8_t scope = RT_SCOPE_NOWHERE;
+ Iterator i;
/* if we have carrier, check what addresses we have */
- LIST_FOREACH(addresses, address, link->addresses) {
- if (address->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED))
+ SET_FOREACH(address, link->addresses, i) {
+ if (!address_is_ready(address))
continue;
if (address->scope < scope)
@@ -2488,7 +2386,6 @@ int link_save(Link *link) {
if (space)
fputc(' ', f);
serialize_in6_addrs(f, in6_addrs, r);
- space = true;
}
}
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index f588faf209..b81bae3830 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -83,7 +83,7 @@ struct Link {
unsigned link_messages;
unsigned enslaving;
- LIST_HEAD(Address, addresses);
+ Set *addresses;
sd_dhcp_client *dhcp_client;
sd_dhcp_lease *dhcp_lease;
@@ -91,6 +91,7 @@ struct Link {
uint16_t original_mtu;
unsigned dhcp4_messages;
bool dhcp4_configured;
+ bool dhcp6_configured;
sd_ipv4ll *ipv4ll;
bool ipv4ll_address;
@@ -119,8 +120,8 @@ int link_get(Manager *m, int ifindex, Link **ret);
int link_add(Manager *manager, sd_netlink_message *message, Link **ret);
void link_drop(Link *link);
-int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
-int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
+int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata);
void link_enter_failed(Link *link);
int link_initialized(Link *link, struct udev_device *device);
@@ -128,7 +129,6 @@ int link_initialized(Link *link, struct udev_device *device);
void link_client_handler(Link *link);
int link_update(Link *link, sd_netlink_message *message);
-int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata);
int link_save(Link *link);
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index b4259cafef..07e47b668c 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -277,6 +277,166 @@ static int manager_connect_udev(Manager *m) {
return 0;
}
+int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
+ Manager *m = userdata;
+ Link *link = NULL;
+ uint16_t type;
+ unsigned char flags;
+ int family;
+ unsigned char prefixlen;
+ unsigned char scope;
+ union in_addr_union in_addr;
+ struct ifa_cacheinfo cinfo;
+ Address *address = NULL;
+ char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
+ const char *valid_str = NULL;
+ int r, ifindex;
+
+ assert(rtnl);
+ assert(message);
+ assert(m);
+
+ if (sd_netlink_message_is_error(message)) {
+ r = sd_netlink_message_get_errno(message);
+ if (r < 0)
+ log_warning_errno(r, "rtnl: failed to receive address: %m");
+
+ return 0;
+ }
+
+ r = sd_netlink_message_get_type(message, &type);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get message type: %m");
+ return 0;
+ } else if (type != RTM_NEWADDR && type != RTM_DELADDR) {
+ log_warning("rtnl: received unexpected message type when processing address");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_ifindex(message, &ifindex);
+ if (r < 0) {
+ log_warning_errno(r, "rtnl: could not get ifindex from address: %m");
+ return 0;
+ } else if (ifindex <= 0) {
+ log_warning("rtnl: received address message with invalid ifindex: %d", ifindex);
+ return 0;
+ } else {
+ r = link_get(m, ifindex, &link);
+ if (r < 0 || !link) {
+ /* when enumerating we might be out of sync, but we will
+ * get the address again, so just ignore it */
+ if (!m->enumerating)
+ log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex);
+ return 0;
+ }
+ }
+
+ r = sd_rtnl_message_addr_get_family(message, &family);
+ if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) {
+ log_link_warning(link, "rtnl: received address with invalid family, ignoring.");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_scope(message, &scope);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m");
+ return 0;
+ }
+
+ r = sd_rtnl_message_addr_get_flags(message, &flags);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m");
+ return 0;
+ }
+
+ switch (family) {
+ case AF_INET:
+ r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ case AF_INET6:
+ r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m");
+ return 0;
+ }
+
+ break;
+
+ default:
+ assert_not_reached("invalid address family");
+ }
+
+ if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) {
+ log_link_warning(link, "Could not print address");
+ return 0;
+ }
+
+ r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
+ if (r >= 0) {
+ if (cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME)
+ valid_str = "ever";
+ else
+ valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
+ cinfo.ifa_valid * USEC_PER_SEC,
+ USEC_PER_SEC);
+ }
+
+ address_get(link, family, &in_addr, prefixlen, &address);
+
+ switch (type) {
+ case RTM_NEWADDR:
+ if (address) {
+ log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+
+ address->scope = scope;
+ address->flags = flags;
+ address->cinfo = cinfo;
+
+ } else {
+ r = address_add(link, family, &in_addr, prefixlen, &address);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to add address %s/%u: %m", buf, prefixlen);
+ return 0;
+ } else
+ log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+
+ address->scope = scope;
+ address->flags = flags;
+ address->cinfo = cinfo;
+
+ link_save(link);
+ }
+
+ break;
+
+ case RTM_DELADDR:
+
+ if (address) {
+ log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+ address_drop(address);
+ } else
+ log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, prefixlen, valid_str);
+
+ break;
+ default:
+ assert_not_reached("Received invalid RTNL message type");
+ }
+
+ return 1;
+}
+
static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
Manager *m = userdata;
Link *link = NULL;
@@ -410,11 +570,11 @@ static int manager_connect_rtnl(Manager *m) {
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
+ r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &manager_rtnl_process_address, m);
if (r < 0)
return r;
- r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
+ r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &manager_rtnl_process_address, m);
if (r < 0)
return r;
@@ -477,14 +637,6 @@ void manager_free(Manager *m) {
free(m->state_file);
- sd_event_source_unref(m->udev_event_source);
- udev_monitor_unref(m->udev_monitor);
- udev_unref(m->udev);
-
- sd_bus_unref(m->bus);
- sd_bus_slot_unref(m->prepare_for_sleep_slot);
- sd_event_source_unref(m->bus_retry_event_source);
-
while ((link = hashmap_first(m->links)))
link_unref(link);
hashmap_free(m->links);
@@ -504,6 +656,14 @@ void manager_free(Manager *m) {
sd_netlink_unref(m->rtnl);
sd_event_unref(m->event);
+ sd_event_source_unref(m->udev_event_source);
+ udev_monitor_unref(m->udev_monitor);
+ udev_unref(m->udev);
+
+ sd_bus_unref(m->bus);
+ sd_bus_slot_unref(m->prepare_for_sleep_slot);
+ sd_event_source_unref(m->bus_retry_event_source);
+
free(m);
}
@@ -633,7 +793,7 @@ int manager_rtnl_enumerate_addresses(Manager *m) {
m->enumerating = true;
- k = link_rtnl_process_address(m->rtnl, addr, m);
+ k = manager_rtnl_process_address(m->rtnl, addr, m);
if (k < 0)
r = k;
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index 12e2321674..bcaba57937 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -357,12 +357,12 @@ int config_parse_arp_ip_target_address(const char *unit,
r = in_addr_from_string_auto(n, &f, &buffer->ip);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
return 0;
}
if (f != AF_INET) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
return 0;
}
@@ -373,7 +373,7 @@ int config_parse_arp_ip_target_address(const char *unit,
}
if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX)
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
return 0;
}
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index fd6af7e99b..2eeb86a683 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -20,12 +20,96 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <net/if.h>
#include "networkd-netdev-bridge.h"
#include "missing.h"
+#include "netlink-util.h"
+
+/* callback for brige netdev's parameter set */
+static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ _cleanup_netdev_unref_ NetDev *netdev = userdata;
+ int r;
+
+ assert(netdev);
+ assert(m);
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0) {
+ log_netdev_warning_errno(netdev, r, "Bridge parameters could not be set: %m");
+ return 1;
+ }
+
+ log_netdev_debug(netdev, "Bridge parametres set success");
+
+ return 1;
+}
+
+static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+ _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
+ Bridge *b;
+ int r;
+
+ assert(netdev);
+
+ b = BRIDGE(netdev);
+
+ assert(b);
+
+ r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, netdev->ifindex);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m");
+
+ r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not set netlink flags: %m");
+
+ r = sd_netlink_message_open_container(req, IFLA_LINKINFO);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_PROTINFO attribute: %m");
+
+ r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind));
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+ if (b->forward_delay > 0) {
+ r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, b->forward_delay / USEC_PER_SEC);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_FORWARD_DELAY attribute: %m");
+ }
+
+ if (b->hello_time > 0) {
+ r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, b->hello_time / USEC_PER_SEC );
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_HELLO_TIME attribute: %m");
+ }
+
+ if (b->max_age > 0) {
+ r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, b->max_age / USEC_PER_SEC);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m");
+ }
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
+
+ r = sd_netlink_message_close_container(req);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m");
+
+ r = sd_netlink_call_async(netdev->manager->rtnl, req, netdev_bridge_set_handler, netdev, 0, NULL);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
+
+ netdev_ref(netdev);
+
+ return r;
+}
const NetDevVTable bridge_vtable = {
.object_size = sizeof(Bridge),
- .sections = "Match\0NetDev\0",
+ .sections = "Match\0NetDev\0Bridge\0",
+ .post_create = netdev_bridge_post_create,
.create_type = NETDEV_CREATE_MASTER,
};
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index a7d02b1c91..d3bd15e0d6 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -27,6 +27,10 @@ typedef struct Bridge Bridge;
struct Bridge {
NetDev meta;
+
+ usec_t forward_delay;
+ usec_t hello_time;
+ usec_t max_age;
};
extern const NetDevVTable bridge_vtable;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index e0bd0e024a..4aac239850 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -86,3 +86,6 @@ Bond.UpDelaySec, config_parse_sec, 0,
Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay)
Bond.ARPIntervalSec, config_parse_sec, 0, offsetof(Bond, arp_interval)
Bond.LearnPacketIntervalSec, config_parse_sec, 0, offsetof(Bond, lp_interval)
+Bridge.HelloTimeSec, config_parse_sec, 0, offsetof(Bridge, hello_time)
+Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age)
+Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay)
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index a906e473b6..c9b7fa96e2 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -395,12 +395,12 @@ int config_parse_tunnel_address(const char *unit,
r = in_addr_from_string_auto(rvalue, &f, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue);
return 0;
}
if (t->family != AF_UNSPEC && t->family != f) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
return 0;
}
@@ -435,13 +435,14 @@ int config_parse_ipv6_flowlabel(const char* unit,
t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
} else {
r = config_parse_int(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata);
- if (r >= 0) {
- if (k > 0xFFFFF)
- log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue);
- else {
- *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL;
- t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
- }
+ if (r < 0)
+ return r;
+
+ if (k > 0xFFFFF)
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue);
+ else {
+ *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL;
+ t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
}
}
@@ -471,13 +472,12 @@ int config_parse_encap_limit(const char* unit,
else {
r = safe_atoi(rvalue, &k);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue);
return 0;
}
if (k > 255 || k < 0)
- log_syntax(unit, LOG_ERR, filename, line, k, "Invalid Tunnel Encapsulation value, ignoring: %d", k);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k);
else {
t->encap_limit = k;
t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index 2518e2732b..03a599c0d4 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -131,14 +131,12 @@ int config_parse_vxlan_group_address(const char *unit,
r = in_addr_from_string_auto(rvalue, &f, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "vxlan multicast group address is invalid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "vxlan multicast group address is invalid, ignoring assignment: %s", rvalue);
return 0;
}
- if(v->family != AF_UNSPEC && v->family != f) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "vxlan multicast group incompatible, ignoring assignment: %s", rvalue);
+ if (v->family != AF_UNSPEC && v->family != f) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan multicast group incompatible, ignoring assignment: %s", rvalue);
return 0;
}
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index ff1edf2c39..3d4865a780 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -245,6 +245,9 @@ static int netdev_enter_ready(NetDev *netdev) {
free(callback);
}
+ if (NETDEV_VTABLE(netdev)->post_create)
+ NETDEV_VTABLE(netdev)->post_create(netdev, NULL, NULL);
+
return 0;
}
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 1f8510c4f7..3b9ab27b67 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -141,6 +141,9 @@ struct NetDevVTable {
/* create netdev, if not done via rtnl */
int (*create)(NetDev *netdev);
+ /* perform additional configuration after netdev has been createad */
+ int (*post_create)(NetDev *netdev, Link *link, sd_netlink_message *message);
+
/* verify that compulsory configuration options were specified */
int (*config_verify)(NetDev *netdev, const char *filename);
};
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 10ca9dae35..b6f70e191d 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -15,88 +15,90 @@ struct ConfigPerfItem;
%struct-type
%includes
%%
-Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac)
-Match.Path, config_parse_strv, 0, offsetof(Network, match_path)
-Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver)
-Match.Type, config_parse_strv, 0, offsetof(Network, match_type)
-Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name)
-Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host)
-Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt)
-Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel)
-Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch)
-Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac)
-Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu)
-Network.Description, config_parse_string, 0, offsetof(Network, description)
-Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge)
-Network.Bond, config_parse_netdev, 0, offsetof(Network, bond)
-Network.VLAN, config_parse_netdev, 0, 0
-Network.MACVLAN, config_parse_netdev, 0, 0
-Network.MACVTAP, config_parse_netdev, 0, 0
-Network.IPVLAN, config_parse_netdev, 0, 0
-Network.VXLAN, config_parse_netdev, 0, 0
-Network.Tunnel, config_parse_tunnel, 0, 0
-Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp)
-Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server)
-Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local)
-Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
-Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
-Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp)
-Network.Address, config_parse_address, 0, 0
-Network.Gateway, config_parse_gateway, 0, 0
-Network.Domains, config_parse_domains, 0, offsetof(Network, domains)
-Network.DNS, config_parse_strv, 0, offsetof(Network, dns)
-Network.LLMNR, config_parse_resolve, 0, offsetof(Network, llmnr)
-Network.NTP, config_parse_strv, 0, offsetof(Network, ntp)
-Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward)
-Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade)
-Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions)
-Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
-Address.Address, config_parse_address, 0, 0
-Address.Peer, config_parse_address, 0, 0
-Address.Broadcast, config_parse_broadcast, 0, 0
-Address.Label, config_parse_label, 0, 0
-Route.Gateway, config_parse_gateway, 0, 0
-Route.Destination, config_parse_destination, 0, 0
-Route.Source, config_parse_destination, 0, 0
-Route.Metric, config_parse_route_priority, 0, 0
-Route.Scope, config_parse_route_scope, 0, 0
-DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
-DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
-DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp)
-DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
-DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname)
-DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains)
-DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes)
-DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost)
-DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, hostname)
-DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
-DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
-DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
-DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
-DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_timezone)
-DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
-DHCPServer.DefaultLeaseTimeSec,config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
-DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns)
-DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0
-DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp)
-DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0
-DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone)
-DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone)
-DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset)
-DHCPServer.PoolSize, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_size)
-Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost)
-Bridge.UseBPDU, config_parse_bool, 0, offsetof(Network, use_bpdu)
-Bridge.HairPin, config_parse_bool, 0, offsetof(Network, hairpin)
-Bridge.FastLeave, config_parse_bool, 0, offsetof(Network, fast_leave)
-Bridge.AllowPortToBeRoot, config_parse_bool, 0, offsetof(Network, allow_port_to_be_root)
-Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood)
-BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
-BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
+Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac)
+Match.Path, config_parse_strv, 0, offsetof(Network, match_path)
+Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver)
+Match.Type, config_parse_strv, 0, offsetof(Network, match_type)
+Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name)
+Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host)
+Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt)
+Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel)
+Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch)
+Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac)
+Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu)
+Network.Description, config_parse_string, 0, offsetof(Network, description)
+Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge)
+Network.Bond, config_parse_netdev, 0, offsetof(Network, bond)
+Network.VLAN, config_parse_netdev, 0, 0
+Network.MACVLAN, config_parse_netdev, 0, 0
+Network.MACVTAP, config_parse_netdev, 0, 0
+Network.IPVLAN, config_parse_netdev, 0, 0
+Network.VXLAN, config_parse_netdev, 0, 0
+Network.Tunnel, config_parse_tunnel, 0, 0
+Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp)
+Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server)
+Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local)
+Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
+Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
+Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp)
+Network.Address, config_parse_address, 0, 0
+Network.Gateway, config_parse_gateway, 0, 0
+Network.Domains, config_parse_domains, 0, offsetof(Network, domains)
+Network.DNS, config_parse_strv, 0, offsetof(Network, dns)
+Network.LLMNR, config_parse_resolve, 0, offsetof(Network, llmnr)
+Network.NTP, config_parse_strv, 0, offsetof(Network, ntp)
+Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward)
+Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade)
+Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions)
+Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra)
+Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
+Address.Address, config_parse_address, 0, 0
+Address.Peer, config_parse_address, 0, 0
+Address.Broadcast, config_parse_broadcast, 0, 0
+Address.Label, config_parse_label, 0, 0
+Route.Gateway, config_parse_gateway, 0, 0
+Route.Destination, config_parse_destination, 0, 0
+Route.Source, config_parse_destination, 0, 0
+Route.Metric, config_parse_route_priority, 0, 0
+Route.Scope, config_parse_route_scope, 0, 0
+Route.PreferredSource, config_parse_preferred_src, 0, 0
+DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
+DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
+DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp)
+DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
+DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname)
+DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains)
+DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes)
+DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost)
+DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, hostname)
+DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
+DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
+DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
+DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
+DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_timezone)
+DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
+DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
+DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns)
+DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0
+DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp)
+DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0
+DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone)
+DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone)
+DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset)
+DHCPServer.PoolSize, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_size)
+Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost)
+Bridge.UseBPDU, config_parse_bool, 0, offsetof(Network, use_bpdu)
+Bridge.HairPin, config_parse_bool, 0, offsetof(Network, hairpin)
+Bridge.FastLeave, config_parse_bool, 0, offsetof(Network, fast_leave)
+Bridge.AllowPortToBeRoot, config_parse_bool, 0, offsetof(Network, allow_port_to_be_root)
+Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood)
+BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
+BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
/* backwards compatibility: do not add new entries to this section */
-Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local)
-DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
-DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
-DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname)
-DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains)
-DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains)
-DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
+Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local)
+DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns)
+DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu)
+DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname)
+DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains)
+DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains)
+DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index ee14401982..bdee7f1923 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -120,6 +120,7 @@ static int network_load_one(Manager *manager, const char *filename) {
network->link_local = ADDRESS_FAMILY_IPV6;
network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO;
+ network->ipv6_accept_ra = -1;
r = config_parse(NULL, filename, file,
"Match\0"
@@ -325,12 +326,12 @@ int network_get(Manager *manager, struct udev_device *device,
(void) safe_atou8(attr, &name_assign_type);
if (name_assign_type == NET_NAME_ENUM)
- log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname",
- IFNAMSIZ, ifname, network->filename);
+ log_warning("%s: found matching network '%s', based on potentially unpredictable ifname",
+ ifname, network->filename);
else
- log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+ log_debug("%s: found matching network '%s'", ifname, network->filename);
} else
- log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename);
+ log_debug("%s: found matching network '%s'", ifname, network->filename);
*ret = network;
return 0;
@@ -408,21 +409,18 @@ int config_parse_netdev(const char *unit,
kind = netdev_kind_from_string(kind_string);
if (kind == _NETDEV_KIND_INVALID) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid NetDev kind: %s", lvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
return 0;
}
r = netdev_get(network->manager, rvalue, &netdev);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
if (netdev->kind != kind) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
@@ -442,9 +440,7 @@ int config_parse_netdev(const char *unit,
case NETDEV_KIND_VXLAN:
r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Can not add VLAN '%s' to network: %m",
- rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Can not add VLAN '%s' to network: %m", rvalue);
return 0;
}
@@ -483,7 +479,7 @@ int config_parse_domains(const char *unit,
STRV_FOREACH(domain, *domains) {
if (is_localhost(*domain))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain);
else {
r = dns_name_is_valid(*domain);
if (r <= 0 && !streq(*domain, "*")) {
@@ -539,7 +535,7 @@ int config_parse_tunnel(const char *unit,
netdev->kind != NETDEV_KIND_VTI6 &&
netdev->kind != NETDEV_KIND_IP6TNL
) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ log_syntax(unit, LOG_ERR, filename, line, 0,
"NetDev is not a tunnel, ignoring assignment: %s", rvalue);
return 0;
}
@@ -624,7 +620,7 @@ int config_parse_dhcp(
else if (streq(rvalue, "both"))
s = ADDRESS_FAMILY_YES;
else {
- log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
return 0;
}
}
@@ -669,13 +665,13 @@ int config_parse_ipv6token(
}
r = in_addr_is_null(AF_INET6, &buffer);
- if (r < 0) {
+ if (r != 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue);
return 0;
}
if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue);
return 0;
}
@@ -729,7 +725,7 @@ int config_parse_ipv6_privacy_extensions(
if (streq(rvalue, "kernel"))
s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
else {
- log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
return 0;
}
}
@@ -764,7 +760,7 @@ int config_parse_hostname(
return r;
if (!hostname_is_valid(hn, false)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Hostname is not valid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
free(hn);
return 0;
}
@@ -798,7 +794,7 @@ int config_parse_timezone(
return r;
if (!timezone_is_valid(tz)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Timezone is not valid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
free(tz);
return 0;
}
@@ -843,7 +839,7 @@ int config_parse_dhcp_server_dns(
return 0;
if (inet_pton(AF_INET, w, &a) <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server address, ignoring: %s", w);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
continue;
}
@@ -882,7 +878,7 @@ int config_parse_dhcp_server_ntp(
r = extract_first_word(&p, &w, NULL, 0);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, r, line, "Failed to extract word, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
return 0;
}
@@ -890,7 +886,7 @@ int config_parse_dhcp_server_ntp(
return 0;
if (inet_pton(AF_INET, w, &a) <= 0) {
- log_syntax(unit, LOG_ERR, filename, r, line, "Failed to parse NTP server address, ignoring: %s", w);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
continue;
}
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index c3439a70ba..2a43b6b347 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -120,6 +120,8 @@ struct Network {
AddressFamilyBoolean ip_forward;
bool ip_masquerade;
+ int ipv6_accept_ra;
+
union in_addr_union ipv6_token;
IPv6PrivacyExtensions ipv6_privacy_extensions;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index fbaad40579..1c8302ffaa 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -26,8 +26,26 @@
#include "networkd.h"
#include "networkd-route.h"
+int route_new(Route **ret, unsigned char rtm_protocol) {
+ _cleanup_route_free_ Route *route = NULL;
+
+ route = new0(Route, 1);
+ if (!route)
+ return -ENOMEM;
+
+ route->family = AF_UNSPEC;
+ route->scope = RT_SCOPE_UNIVERSE;
+ route->protocol = rtm_protocol;
+
+ *ret = route;
+ route = NULL;
+
+ return 0;
+}
+
int route_new_static(Network *network, unsigned section, Route **ret) {
_cleanup_route_free_ Route *route = NULL;
+ int r;
if (section) {
route = hashmap_get(network->routes_by_section,
@@ -40,13 +58,9 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
}
}
- route = new0(Route, 1);
- if (!route)
- return -ENOMEM;
-
- route->family = AF_UNSPEC;
- route->scope = RT_SCOPE_UNIVERSE;
- route->protocol = RTPROT_STATIC;
+ r = route_new(&route, RTPROT_STATIC);
+ if (r < 0)
+ return r;
route->network = network;
@@ -64,23 +78,6 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
return 0;
}
-int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
- _cleanup_route_free_ Route *route = NULL;
-
- route = new0(Route, 1);
- if (!route)
- return -ENOMEM;
-
- route->family = AF_UNSPEC;
- route->scope = RT_SCOPE_UNIVERSE;
- route->protocol = rtm_protocol;
-
- *ret = route;
- route = NULL;
-
- return 0;
-}
-
void route_free(Route *route) {
if (!route)
return;
@@ -96,7 +93,7 @@ void route_free(Route *route) {
free(route);
}
-int route_drop(Route *route, Link *link,
+int route_remove(Route *route, Link *link,
sd_netlink_message_handler_t callback) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
int r;
@@ -294,8 +291,7 @@ int config_parse_gateway(const char *unit,
r = in_addr_from_string_auto(rvalue, &f, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Route is invalid, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue);
return 0;
}
@@ -306,6 +302,46 @@ int config_parse_gateway(const char *unit,
return 0;
}
+int config_parse_preferred_src(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = userdata;
+ _cleanup_route_free_ Route *n = NULL;
+ union in_addr_union buffer;
+ int r, f;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = route_new_static(network, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = in_addr_from_string_auto(rvalue, &f, &buffer);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Preferred source is invalid, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ n->family = f;
+ n->prefsrc_addr = buffer;
+ n = NULL;
+
+ return 0;
+}
+
int config_parse_destination(const char *unit,
const char *filename,
unsigned line,
@@ -345,14 +381,12 @@ int config_parse_destination(const char *unit,
r = in_addr_from_string_auto(address, &f, &buffer);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Destination is invalid, ignoring assignment: %s", address);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Destination is invalid, ignoring assignment: %s", address);
return 0;
}
if (f != AF_INET && f != AF_INET6) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unknown address family, ignoring assignment: %s", address);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown address family, ignoring assignment: %s", address);
return 0;
}
@@ -360,8 +394,7 @@ int config_parse_destination(const char *unit,
if (e) {
r = safe_atou8(e + 1, &prefixlen);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
return 0;
}
} else {
@@ -456,8 +489,7 @@ int config_parse_route_scope(const char *unit,
else if (streq(rvalue, "global"))
n->scope = RT_SCOPE_UNIVERSE;
else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unknown route scope: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue);
return 0;
}
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index d090b9c91e..e3ed1be866 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -46,15 +46,16 @@ struct Route {
};
int route_new_static(Network *network, unsigned section, Route **ret);
-int route_new_dynamic(Route **ret, unsigned char rtm_protocol);
+int route_new(Route **ret, unsigned char rtm_protocol);
void route_free(Route *route);
int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
-int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback);
+int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback);
DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
#define _cleanup_route_free_ _cleanup_(route_freep)
int config_parse_gateway(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_preferred_src(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_destination(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_route_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_route_scope(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c
index a41cd86239..dde6b327ed 100644
--- a/src/network/networkd-util.c
+++ b/src/network/networkd-util.c
@@ -82,7 +82,7 @@ int config_parse_address_family_boolean_with_kernel(
if (streq(rvalue, "kernel"))
s = _ADDRESS_FAMILY_BOOLEAN_INVALID;
else {
- log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding= option, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPForwarding= option, ignoring: %s", rvalue);
return 0;
}
}
@@ -133,7 +133,7 @@ int config_parse_resolve(
s = resolve_support_from_string(rvalue);
if (s < 0){
- log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse %s= option, ignoring: %s", lvalue, rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse %s= option, ignoring: %s", lvalue, rvalue);
return 0;
}
diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c
index d958b48771..3220c4b7ef 100644
--- a/src/network/networkd-wait-online.c
+++ b/src/network/networkd-wait-online.c
@@ -21,10 +21,10 @@
#include <getopt.h>
#include "sd-daemon.h"
-#include "strv.h"
-#include "build.h"
-#include "signal-util.h"
+
#include "networkd-wait-online.h"
+#include "signal-util.h"
+#include "strv.h"
static bool arg_quiet = false;
static usec_t arg_timeout = 120 * USEC_PER_SEC;
@@ -79,9 +79,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'i':
if (strv_extend(&arg_interfaces, optarg) < 0)
diff --git a/src/network/networkd.h b/src/network/networkd.h
index eea57ac158..cbec6d5b7e 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -80,6 +80,8 @@ bool manager_should_reload(Manager *m);
int manager_rtnl_enumerate_links(Manager *m);
int manager_rtnl_enumerate_addresses(Manager *m);
+int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata);
+
int manager_send_changed(Manager *m, const char *property, ...) _sentinel_;
int manager_save(Manager *m);
diff --git a/src/network/test-network.c b/src/network/test-network.c
index 5909cc790e..bac1d6781d 100644
--- a/src/network/test-network.c
+++ b/src/network/test-network.c
@@ -143,8 +143,8 @@ static void test_network_get(Manager *manager, struct udev_device *loopback) {
static void test_address_equality(void) {
_cleanup_address_free_ Address *a1 = NULL, *a2 = NULL;
- assert_se(address_new_dynamic(&a1) >= 0);
- assert_se(address_new_dynamic(&a2) >= 0);
+ assert_se(address_new(&a1) >= 0);
+ assert_se(address_new(&a2) >= 0);
assert_se(address_equal(NULL, NULL));
assert_se(!address_equal(a1, NULL));
@@ -158,17 +158,18 @@ static void test_address_equality(void) {
assert_se(address_equal(a1, a2));
assert_se(inet_pton(AF_INET, "192.168.3.9", &a1->in_addr.in));
- assert_se(address_equal(a1, a2));
+ assert_se(!address_equal(a1, a2));
assert_se(inet_pton(AF_INET, "192.168.3.9", &a2->in_addr.in));
assert_se(address_equal(a1, a2));
+ assert_se(inet_pton(AF_INET, "192.168.3.10", &a1->in_addr_peer.in));
+ assert_se(address_equal(a1, a2));
+ assert_se(inet_pton(AF_INET, "192.168.3.11", &a2->in_addr_peer.in));
+ assert_se(address_equal(a1, a2));
a1->prefixlen = 10;
assert_se(!address_equal(a1, a2));
a2->prefixlen = 10;
assert_se(address_equal(a1, a2));
- assert_se(inet_pton(AF_INET, "192.168.3.10", &a2->in_addr.in));
- assert_se(address_equal(a1, a2));
-
a1->family = AF_INET6;
assert_se(!address_equal(a1, a2));
diff --git a/src/notify/notify.c b/src/notify/notify.c
index c303bcf718..805ea1a627 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -19,20 +19,19 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <getopt.h>
#include <errno.h>
-#include <unistd.h>
+#include <getopt.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
-#include "systemd/sd-daemon.h"
+#include "sd-daemon.h"
-#include "strv.h"
-#include "util.h"
-#include "log.h"
-#include "build.h"
#include "env-util.h"
#include "formats-util.h"
+#include "log.h"
+#include "strv.h"
+#include "util.h"
static bool arg_ready = false;
static pid_t arg_pid = 0;
@@ -85,9 +84,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_READY:
arg_ready = true;
@@ -191,7 +188,7 @@ int main(int argc, char* argv[]) {
goto finish;
}
- r = sd_pid_notify(arg_pid, false, n);
+ r = sd_pid_notify(arg_pid ? arg_pid : getppid(), false, n);
if (r < 0) {
log_error_errno(r, "Failed to notify init system: %m");
goto finish;
diff --git a/src/nspawn/nspawn-expose-ports.c b/src/nspawn/nspawn-expose-ports.c
index 38250b6e02..3658f45381 100644
--- a/src/nspawn/nspawn-expose-ports.c
+++ b/src/nspawn/nspawn-expose-ports.c
@@ -183,17 +183,8 @@ int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *ex
}
int expose_port_send_rtnl(int send_fd) {
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
_cleanup_close_ int fd = -1;
- ssize_t k;
+ int r;
assert(send_fd >= 0);
@@ -201,19 +192,11 @@ int expose_port_send_rtnl(int send_fd) {
if (fd < 0)
return log_error_errno(errno, "Failed to allocate container netlink: %m");
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
/* Store away the fd in the socket, so that it stays open as
* long as we run the child */
- k = sendmsg(send_fd, &mh, MSG_NOSIGNAL);
- if (k < 0)
- return log_error_errno(errno, "Failed to send netlink fd: %m");
+ r = send_one_fd(send_fd, fd, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to send netlink fd: %m");
return 0;
}
@@ -224,33 +207,16 @@ int expose_port_watch_rtnl(
sd_netlink_message_handler_t handler,
union in_addr_union *exposed,
sd_netlink **ret) {
-
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
_cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
int fd, r;
- ssize_t k;
assert(event);
assert(recv_fd >= 0);
assert(ret);
- k = recvmsg(recv_fd, &mh, MSG_NOSIGNAL);
- if (k < 0)
- return log_error_errno(errno, "Failed to recv netlink fd: %m");
-
- cmsg = CMSG_FIRSTHDR(&mh);
- assert(cmsg->cmsg_level == SOL_SOCKET);
- assert(cmsg->cmsg_type == SCM_RIGHTS);
- assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
- memcpy(&fd, CMSG_DATA(cmsg), sizeof(int));
+ fd = receive_one_fd(recv_fd, 0);
+ if (fd < 0)
+ return log_error_errno(fd, "Failed to recv netlink fd: %m");
r = sd_netlink_open_fd(&rtnl, fd);
if (r < 0) {
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index 2bca39f45d..6c8b1d7a26 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -216,8 +216,55 @@ static int tmpfs_patch_options(
return !!buf;
}
+int mount_sysfs(const char *dest) {
+ const char *full, *top, *x;
+
+ top = prefix_roota(dest, "/sys");
+ full = prefix_roota(top, "/full");
+
+ (void) mkdir(full, 0755);
+
+ if (mount("sysfs", full, "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) < 0)
+ return log_error_errno(errno, "Failed to mount sysfs to %s: %m", full);
+
+ FOREACH_STRING(x, "block", "bus", "class", "dev", "devices", "kernel") {
+ _cleanup_free_ char *from = NULL, *to = NULL;
+
+ from = prefix_root(full, x);
+ if (!from)
+ return log_oom();
+
+ to = prefix_root(top, x);
+ if (!to)
+ return log_oom();
+
+ (void) mkdir(to, 0755);
+
+ if (mount(from, to, NULL, MS_BIND, NULL) < 0)
+ return log_error_errno(errno, "Failed to mount /sys/%s into place: %m", x);
+
+ if (mount(NULL, to, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL) < 0)
+ return log_error_errno(errno, "Failed to mount /sys/%s read-only: %m", x);
+ }
+
+ if (umount(full) < 0)
+ return log_error_errno(errno, "Failed to unmount %s: %m", full);
+
+ if (rmdir(full) < 0)
+ return log_error_errno(errno, "Failed to remove %s: %m", full);
+
+ x = prefix_roota(top, "/fs/kdbus");
+ (void) mkdir(x, 0755);
+
+ if (mount(NULL, top, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL) < 0)
+ return log_error_errno(errno, "Failed to make %s read-only: %m", top);
+
+ return 0;
+}
+
int mount_all(const char *dest,
- bool userns, uid_t uid_shift, uid_t uid_range,
+ bool use_userns, bool in_userns,
+ uid_t uid_shift, uid_t uid_range,
const char *selinux_apifs_context) {
typedef struct MountPoint {
@@ -234,7 +281,7 @@ int mount_all(const char *dest,
{ "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true },
{ "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true }, /* Bind mount first */
{ NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true }, /* Then, make it r/o */
- { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false },
+ { "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false },
{ "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false },
{ "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false },
{ "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false },
@@ -252,7 +299,7 @@ int mount_all(const char *dest,
_cleanup_free_ char *where = NULL, *options = NULL;
const char *o;
- if (userns != mount_table[k].userns)
+ if (in_userns != mount_table[k].userns)
continue;
where = prefix_root(dest, mount_table[k].where);
@@ -278,7 +325,7 @@ int mount_all(const char *dest,
o = mount_table[k].options;
if (streq_ptr(mount_table[k].type, "tmpfs")) {
- r = tmpfs_patch_options(o, userns, uid_shift, uid_range, selinux_apifs_context, &options);
+ r = tmpfs_patch_options(o, use_userns, uid_shift, uid_range, selinux_apifs_context, &options);
if (r < 0)
return log_oom();
if (r > 0)
@@ -534,7 +581,7 @@ static int mount_legacy_cgroup_hierarchy(const char *dest, const char *controlle
char *to;
int r;
- to = strjoina(dest, "/sys/fs/cgroup/", hierarchy);
+ to = strjoina(strempty(dest), "/sys/fs/cgroup/", hierarchy);
r = path_is_mount_point(to, 0);
if (r < 0 && r != -ENOENT)
@@ -569,6 +616,8 @@ static int mount_legacy_cgroups(
cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");
+ (void) mkdir_p(cgroup_root, 0755);
+
/* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
r = path_is_mount_point(cgroup_root, AT_SYMLINK_FOLLOW);
if (r < 0)
@@ -661,13 +710,15 @@ static int mount_unified_cgroups(const char *dest) {
assert(dest);
- p = strjoina(dest, "/sys/fs/cgroup");
+ p = prefix_roota(dest, "/sys/fs/cgroup");
+
+ (void) mkdir_p(p, 0755);
r = path_is_mount_point(p, AT_SYMLINK_FOLLOW);
if (r < 0)
return log_error_errno(r, "Failed to determine if %s is mounted already: %m", p);
if (r > 0) {
- p = strjoina(dest, "/sys/fs/cgroup/cgroup.procs");
+ p = prefix_roota(dest, "/sys/fs/cgroup/cgroup.procs");
if (access(p, F_OK) >= 0)
return 0;
if (errno != ENOENT)
diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h
index 5abd44cc4b..54cab87665 100644
--- a/src/nspawn/nspawn-mount.h
+++ b/src/nspawn/nspawn-mount.h
@@ -57,7 +57,8 @@ int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s);
int custom_mount_compare(const void *a, const void *b);
-int mount_all(const char *dest, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
+int mount_all(const char *dest, bool use_userns, bool in_userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
+int mount_sysfs(const char *dest);
int mount_cgroups(const char *dest, bool unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
int mount_systemd_cgroup_writable(const char *dest, bool unified_requested);
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index 419f5d1c40..b920391b38 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -152,7 +152,7 @@ int config_parse_capability(
cap = capability_from_name(word);
if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, cap, "Failed to parse capability, ignoring: %s", word);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability, ignoring: %s", word);
continue;
}
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 5702df8ab4..ab93f98df4 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -50,7 +50,6 @@
#include "base-filesystem.h"
#include "blkid-util.h"
#include "btrfs-util.h"
-#include "build.h"
#include "cap-list.h"
#include "capability.h"
#include "cgroup-util.h"
@@ -84,12 +83,12 @@
#include "udev-util.h"
#include "util.h"
-#include "nspawn-settings.h"
+#include "nspawn-cgroup.h"
+#include "nspawn-expose-ports.h"
#include "nspawn-mount.h"
#include "nspawn-network.h"
-#include "nspawn-expose-ports.h"
-#include "nspawn-cgroup.h"
#include "nspawn-register.h"
+#include "nspawn-settings.h"
#include "nspawn-setuid.h"
typedef enum ContainerStatus {
@@ -414,9 +413,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'D':
r = set_sanitized_path(&arg_directory, optarg);
@@ -1264,16 +1261,7 @@ static int setup_dev_console(const char *dest, const char *console) {
static int setup_kmsg(const char *dest, int kmsg_socket) {
const char *from, *to;
_cleanup_umask_ mode_t u;
- int fd, k;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
+ int fd, r;
assert(kmsg_socket >= 0);
@@ -1298,21 +1286,13 @@ static int setup_kmsg(const char *dest, int kmsg_socket) {
if (fd < 0)
return log_error_errno(errno, "Failed to open fifo: %m");
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
- mh.msg_controllen = cmsg->cmsg_len;
-
/* Store away the fd in the socket, so that it stays open as
* long as we run the child */
- k = sendmsg(kmsg_socket, &mh, MSG_NOSIGNAL);
+ r = send_one_fd(kmsg_socket, fd, 0);
safe_close(fd);
- if (k < 0)
- return log_error_errno(errno, "Failed to send FIFO fd: %m");
+ if (r < 0)
+ return log_error_errno(r, "Failed to send FIFO fd: %m");
/* And now make the FIFO unavailable as /run/kmsg... */
(void) unlink(from);
@@ -2299,8 +2279,6 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) {
return r;
}
-static void nop_handler(int sig) {}
-
static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
pid_t pid;
@@ -2472,7 +2450,11 @@ static int inner_child(
}
}
- r = mount_all(NULL, true, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+ r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+ if (r < 0)
+ return r;
+
+ r = mount_sysfs(NULL);
if (r < 0)
return r;
@@ -2723,7 +2705,7 @@ static int outer_child(
return log_error_errno(r, "Failed to make tree read-only: %m");
}
- r = mount_all(directory, false, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+ r = mount_all(directory, arg_userns, false, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
if (r < 0)
return r;
@@ -2804,6 +2786,8 @@ static int outer_child(
}
pid_socket = safe_close(pid_socket);
+ kmsg_socket = safe_close(kmsg_socket);
+ rtnl_socket = safe_close(rtnl_socket);
return 0;
}
@@ -3256,7 +3240,7 @@ int main(int argc, char *argv[]) {
ContainerStatus container_status;
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
static const struct sigaction sa = {
- .sa_handler = nop_handler,
+ .sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP,
};
int ifi = 0;
@@ -3353,8 +3337,7 @@ int main(int argc, char *argv[]) {
barrier_set_role(&barrier, BARRIER_PARENT);
- fdset_free(fds);
- fds = NULL;
+ fds = fdset_free(fds);
kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
@@ -3489,8 +3472,8 @@ int main(int argc, char *argv[]) {
}
/* Let the child know that we are ready and wait that the child is completely ready now. */
- if (!barrier_place_and_sync(&barrier)) { /* #5 */
- log_error("Client died too early.");
+ if (!barrier_place_and_sync(&barrier)) { /* #4 */
+ log_error("Child died too early.");
r = -ESRCH;
goto finish;
}
@@ -3529,7 +3512,7 @@ int main(int argc, char *argv[]) {
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
- r = pty_forward_new(event, master, true, !interactive, &forward);
+ r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_VHANGUP | (interactive ? 0 : PTY_FORWARD_READ_ONLY), &forward);
if (r < 0) {
log_error_errno(r, "Failed to create PTY forwarder: %m");
goto finish;
diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c
index 5758ea1569..604130ed25 100644
--- a/src/nss-mymachines/nss-mymachines.c
+++ b/src/nss-mymachines/nss-mymachines.c
@@ -485,7 +485,7 @@ enum nss_status _nss_mymachines_getpwuid_r(
uint32_t mapped;
int r;
- if (UID_IS_INVALID(uid)) {
+ if (!uid_is_valid(uid)) {
r = -EINVAL;
goto fail;
}
@@ -640,7 +640,7 @@ enum nss_status _nss_mymachines_getgrgid_r(
uint32_t mapped;
int r;
- if (GID_IS_INVALID(gid)) {
+ if (!gid_is_valid(gid)) {
r = -EINVAL;
goto fail;
}
diff --git a/src/path/path.c b/src/path/path.c
index f7736a4202..73b7bd2c01 100644
--- a/src/path/path.c
+++ b/src/path/path.c
@@ -19,16 +19,16 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
-#include <getopt.h>
#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
#include <stdlib.h>
#include "sd-path.h"
-#include "build.h"
+
+#include "log.h"
#include "macro.h"
#include "util.h"
-#include "log.h"
static const char *arg_suffix = NULL;
@@ -155,9 +155,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_SUFFIX:
arg_suffix = optarg;
diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c
index 22af092cc0..97516a87a8 100644
--- a/src/resolve-host/resolve-host.c
+++ b/src/resolve-host/resolve-host.c
@@ -23,14 +23,13 @@
#include <getopt.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
+#include "af-list.h"
#include "bus-error.h"
+#include "bus-util.h"
#include "in-addr-util.h"
-#include "af-list.h"
-#include "build.h"
-
-#include "resolved-dns-packet.h"
#include "resolved-def.h"
+#include "resolved-dns-packet.h"
#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
@@ -507,9 +506,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0; /* done */;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
case '4':
arg_family = AF_INET;
diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c
index 12c17003e9..bf1b7c8ab4 100644
--- a/src/resolve/resolved-bus.c
+++ b/src/resolve/resolved-bus.c
@@ -191,7 +191,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
/* This has a cname? Then update the query with the
* new cname. */
- r = dns_query_cname_redirect(q, cname->cname.name);
+ 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);
@@ -220,8 +220,6 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
added++;
}
- // what about the cache?
-
/* If we didn't find anything, then let's restart the
* query, this time with the cname */
if (added <= 0) {
diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c
index 7af63b0a82..cc8d5fa76a 100644
--- a/src/resolve/resolved-conf.c
+++ b/src/resolve/resolved-conf.c
@@ -95,7 +95,7 @@ int config_parse_dnsv(
/* Otherwise add to the list */
r = manager_parse_dns_server(m, ltype, rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
return 0;
}
}
@@ -131,7 +131,7 @@ int config_parse_support(
if (support < 0) {
r = parse_boolean(rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse support level '%s'. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse support level '%s'. Ignoring.", rvalue);
return 0;
}
diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c
index 13ad4ca6bd..89b9b0e1ea 100644
--- a/src/resolve/resolved-dns-answer.c
+++ b/src/resolve/resolved-dns-answer.c
@@ -149,6 +149,19 @@ int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) {
return 0;
}
+int dns_answer_match_soa(DnsResourceKey *key, DnsResourceKey *soa) {
+ if (soa->class != DNS_CLASS_IN)
+ return 0;
+
+ if (soa->type != DNS_TYPE_SOA)
+ return 0;
+
+ if (!dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa)))
+ return 0;
+
+ return 1;
+}
+
int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret) {
unsigned i;
@@ -164,13 +177,7 @@ int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **r
for (i = 0; i < a->n_rrs; i++) {
- if (a->items[i].rr->key->class != DNS_CLASS_IN)
- continue;
-
- if (a->items[i].rr->key->type != DNS_TYPE_SOA)
- continue;
-
- if (dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(a->items[i].rr->key))) {
+ if (dns_answer_match_soa(key, a->items[i].rr->key)) {
*ret = a->items[i].rr;
return 1;
}
diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h
index 0757dd60d0..044d73b19c 100644
--- a/src/resolve/resolved-dns-answer.h
+++ b/src/resolve/resolved-dns-answer.h
@@ -49,6 +49,7 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a);
int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex);
int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl);
int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key);
+int dns_answer_match_soa(DnsResourceKey *key, DnsResourceKey *soa);
int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret);
DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b);
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c
index cbbbed8c8a..ab13636bc1 100644
--- a/src/resolve/resolved-dns-cache.c
+++ b/src/resolve/resolved-dns-cache.c
@@ -277,13 +277,14 @@ static int dns_cache_put_positive(
/* New TTL is 0? Delete the entry... */
if (rr->ttl <= 0) {
- if (dns_cache_remove(c, rr->key)) {
- r = dns_resource_key_to_string(rr->key, &key_str);
- if (r < 0)
- return r;
+ r = dns_resource_key_to_string(rr->key, &key_str);
+ if (r < 0)
+ return r;
+ if (dns_cache_remove(c, rr->key))
log_debug("Removed zero TTL entry from cache: %s", key_str);
- }
+ else
+ log_debug("Not caching zero TTL cache entry: %s", key_str);
return 0;
}
@@ -361,7 +362,7 @@ static int dns_cache_put_negative(
if (r < 0)
return r;
- log_debug("Ignored negative cache entry with zero SOA TTL: %s", key_str);
+ log_debug("Not caching negative entry with zero SOA TTL: %s", key_str);
return 0;
}
@@ -402,7 +403,7 @@ static int dns_cache_put_negative(
int dns_cache_put(
DnsCache *c,
- DnsQuestion *q,
+ DnsResourceKey *key,
int rcode,
DnsAnswer *answer,
unsigned max_rrs,
@@ -410,16 +411,16 @@ int dns_cache_put(
int owner_family,
const union in_addr_union *owner_address) {
+ DnsResourceRecord *soa = NULL;
unsigned cache_keys, i;
int r;
assert(c);
- if (q) {
- /* First, if we were passed a question, delete all matching old RRs,
+ if (key) {
+ /* First, if we were passed a key, delete all matching old RRs,
* so that we only keep complete by_key in place. */
- for (i = 0; i < q->n_keys; i++)
- dns_cache_remove(c, q->keys[i]);
+ dns_cache_remove(c, key);
}
if (!answer)
@@ -437,8 +438,8 @@ int dns_cache_put(
cache_keys = answer->n_rrs;
- if (q)
- cache_keys += q->n_keys;
+ if (key)
+ cache_keys ++;
/* Make some space for our new entries */
dns_cache_make_space(c, cache_keys);
@@ -453,44 +454,63 @@ int dns_cache_put(
goto fail;
}
- if (!q)
+ if (!key)
return 0;
- /* Third, add in negative entries for all keys with no RR */
- for (i = 0; i < q->n_keys; i++) {
- DnsResourceRecord *soa = NULL;
+ /* Third, add in negative entries if the key has no RR */
+ r = dns_answer_contains(answer, key);
+ if (r < 0)
+ goto fail;
+ if (r > 0)
+ return 0;
- r = dns_answer_contains(answer, q->keys[i]);
- if (r < 0)
- goto fail;
- if (r > 0)
- continue;
+ /* See https://tools.ietf.org/html/rfc2308, which
+ * say that a matching SOA record in the packet
+ * is used to to enable negative caching. */
- /* See https://tools.ietf.org/html/rfc2308, which
- * say that a matching SOA record in the packet
- * is used to to enable negative caching. */
+ r = dns_answer_find_soa(answer, key, &soa);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
+ return 0;
- r = dns_answer_find_soa(answer, q->keys[i], &soa);
- if (r < 0)
- goto fail;
- if (r == 0)
- continue;
+ /* Also, if the requested key is an alias, the negative response should
+ be cached for each name in the redirect chain. Any CNAME record in
+ the response is from the redirection chain, though only the final one
+ is guaranteed to be included. This means that we cannot verify the
+ chain and that we need to cache them all as it may be incomplete. */
+ for (i = 0; i < answer->n_rrs; i++) {
+ DnsResourceRecord *answer_rr = answer->items[i].rr;
- r = dns_cache_put_negative(c, q->keys[i], rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address);
- if (r < 0)
- goto fail;
+ if (answer_rr->key->type == DNS_TYPE_CNAME) {
+ _cleanup_(dns_resource_key_unrefp) DnsResourceKey *canonical_key = NULL;
+
+ canonical_key = dns_resource_key_new_redirect(key, answer_rr);
+ if (!canonical_key)
+ goto fail;
+
+ /* Let's not add negative cache entries for records outside the current zone. */
+ if (!dns_answer_match_soa(canonical_key, soa->key))
+ continue;
+
+ r = dns_cache_put_negative(c, canonical_key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address);
+ if (r < 0)
+ goto fail;
+ }
}
+ r = dns_cache_put_negative(c, key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address);
+ if (r < 0)
+ goto fail;
+
return 0;
fail:
/* Adding all RRs failed. Let's clean up what we already
* added, just in case */
- if (q) {
- for (i = 0; i < q->n_keys; i++)
- dns_cache_remove(c, q->keys[i]);
- }
+ if (key)
+ dns_cache_remove(c, key);
for (i = 0; i < answer->n_rrs; i++)
dns_cache_remove(c, answer->items[i].rr->key);
@@ -498,6 +518,29 @@ fail:
return r;
}
+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;
+
+ assert(c);
+ assert(k);
+
+ i = hashmap_get(c->by_key, k);
+ if (i || k->type == DNS_TYPE_CNAME)
+ return i;
+
+ /* 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;
+
+ return i;
+}
+
int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret) {
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
unsigned n = 0;
@@ -527,7 +570,7 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
return 0;
}
- first = hashmap_get(c->by_key, key);
+ first = dns_cache_get_by_key_follow_cname(c, key);
if (!first) {
/* If one question cannot be answered we need to refresh */
diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h
index 1225e58de4..60cf6a4784 100644
--- a/src/resolve/resolved-dns-cache.h
+++ b/src/resolve/resolved-dns-cache.h
@@ -39,7 +39,7 @@ typedef struct DnsCache {
void dns_cache_flush(DnsCache *c);
void dns_cache_prune(DnsCache *c);
-int dns_cache_put(DnsCache *c, DnsQuestion *q, int rcode, DnsAnswer *answer, unsigned max_rrs, usec_t timestamp, int owner_family, const union in_addr_union *owner_address);
+int dns_cache_put(DnsCache *c, DnsResourceKey *key, int rcode, DnsAnswer *answer, unsigned max_rrs, usec_t timestamp, int owner_family, const union in_addr_union *owner_address);
int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **answer);
int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address);
diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c
index c0b4c8ba81..4b1d18b2ef 100644
--- a/src/resolve/resolved-dns-query.c
+++ b/src/resolve/resolved-dns-query.c
@@ -831,7 +831,7 @@ void dns_query_ready(DnsQuery *q) {
dns_query_complete(q, state);
}
-int dns_query_cname_redirect(DnsQuery *q, const char *name) {
+int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) {
_cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL;
int r;
@@ -840,7 +840,7 @@ int dns_query_cname_redirect(DnsQuery *q, const char *name) {
if (q->n_cname_redirects > CNAME_MAX)
return -ELOOP;
- r = dns_question_cname_redirect(q->question, name, &nq);
+ r = dns_question_cname_redirect(q->question, cname, &nq);
if (r < 0)
return r;
diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h
index 93d49301fa..e7063d9678 100644
--- a/src/resolve/resolved-dns-query.h
+++ b/src/resolve/resolved-dns-query.h
@@ -72,7 +72,7 @@ DnsQuery *dns_query_free(DnsQuery *q);
int dns_query_go(DnsQuery *q);
void dns_query_ready(DnsQuery *q);
-int dns_query_cname_redirect(DnsQuery *q, const char *name);
+int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname);
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 c94928d725..1507f22da0 100644
--- a/src/resolve/resolved-dns-question.c
+++ b/src/resolve/resolved-dns-question.c
@@ -242,13 +242,13 @@ int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) {
return 1;
}
-int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **ret) {
+int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret) {
_cleanup_(dns_question_unrefp) DnsQuestion *n = NULL;
bool same = true;
unsigned i;
int r;
- assert(name);
+ assert(cname);
assert(ret);
if (!q) {
@@ -262,7 +262,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **
}
for (i = 0; i < q->n_keys; i++) {
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
+ r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), cname->cname.name);
if (r < 0)
return r;
@@ -286,7 +286,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const char *name, DnsQuestion **
for (i = 0; i < q->n_keys; i++) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL;
- k = dns_resource_key_new(q->keys[i]->class, q->keys[i]->type, name);
+ k = dns_resource_key_new_redirect(q->keys[i], cname);
if (!k)
return -ENOMEM;
diff --git a/src/resolve/resolved-dns-question.h b/src/resolve/resolved-dns-question.h
index 77de0c7a2c..13cd1f20f3 100644
--- a/src/resolve/resolved-dns-question.h
+++ b/src/resolve/resolved-dns-question.h
@@ -46,6 +46,6 @@ int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other);
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 char *name, DnsQuestion **ret);
+int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret);
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuestion*, dns_question_unref);
diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c
index f31644eebc..2bc8cc1639 100644
--- a/src/resolve/resolved-dns-rr.c
+++ b/src/resolve/resolved-dns-rr.c
@@ -48,6 +48,19 @@ DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *
return k;
}
+DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key) {
+ assert(key);
+
+ return dns_resource_key_new(key->class, DNS_TYPE_CNAME, DNS_RESOURCE_KEY_NAME(key));
+}
+
+DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
+ assert(key);
+ assert(cname);
+
+ return dns_resource_key_new(key->class, key->type, cname->cname.name);
+}
+
DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
DnsResourceKey *k;
@@ -133,15 +146,14 @@ int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRec
return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
}
-static unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
const DnsResourceKey *k = i;
- unsigned long ul;
- ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
- ul = ul * hash_key[0] + ul + k->class;
- ul = ul * hash_key[1] + ul + k->type;
+ assert(k);
- return ul;
+ dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
+ siphash24_compress(&k->class, sizeof(k->class), state);
+ siphash24_compress(&k->type, sizeof(k->type), state);
}
static int dns_resource_key_compare_func(const void *a, const void *b) {
diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h
index 8986a298af..9e2207c0aa 100644
--- a/src/resolve/resolved-dns-rr.h
+++ b/src/resolve/resolved-dns-rr.h
@@ -177,6 +177,8 @@ 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_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname);
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);
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index 2ff5b192df..8693911e65 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -137,14 +137,13 @@ void dns_server_packet_lost(DnsServer *s, usec_t usec) {
s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC);
}
-static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void dns_server_hash_func(const void *p, struct siphash *state) {
const DnsServer *s = p;
- uint64_t u;
- siphash24((uint8_t*) &u, &s->address, FAMILY_ADDRESS_SIZE(s->family), hash_key);
- u = u * hash_key[0] + u + s->family;
+ assert(s);
- return u;
+ siphash24_compress(&s->family, sizeof(s->family), state);
+ siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state);
}
static int dns_server_compare_func(const void *a, const void *b) {
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 8092bb514d..b30473dd7e 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -458,7 +458,7 @@ 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, p->question, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender);
+ 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);
diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c
index 904dec6bfc..72c9eb4446 100644
--- a/src/rfkill/rfkill.c
+++ b/src/rfkill/rfkill.c
@@ -19,124 +19,402 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "mkdir.h"
-#include "fileio.h"
+#include <linux/rfkill.h>
+#include <poll.h>
+
#include "libudev.h"
+#include "sd-daemon.h"
+
+#include "fileio.h"
+#include "mkdir.h"
#include "udev-util.h"
+#include "util.h"
-int main(int argc, char *argv[]) {
- _cleanup_udev_unref_ struct udev *udev = NULL;
- _cleanup_udev_device_unref_ struct udev_device *device = NULL;
- _cleanup_free_ char *saved = NULL, *escaped_type = NULL, *escaped_path_id = NULL;
- const char *name, *type, *path_id;
- int r;
+#define EXIT_USEC (5 * USEC_PER_SEC)
- if (argc != 3) {
- log_error("This program requires two arguments.");
- return EXIT_FAILURE;
- }
+static const char* const rfkill_type_table[NUM_RFKILL_TYPES] = {
+ [RFKILL_TYPE_ALL] = "all",
+ [RFKILL_TYPE_WLAN] = "wlan",
+ [RFKILL_TYPE_BLUETOOTH] = "bluetooth",
+ [RFKILL_TYPE_UWB] = "uwb",
+ [RFKILL_TYPE_WIMAX] = "wimax",
+ [RFKILL_TYPE_WWAN] = "wwan",
+ [RFKILL_TYPE_GPS] = "gps",
+ [RFKILL_TYPE_FM] = "fm",
+ [RFKILL_TYPE_NFC] = "nfc",
+};
- log_set_target(LOG_TARGET_AUTO);
- log_parse_environment();
- log_open();
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int);
- umask(0022);
+static int find_device(
+ struct udev *udev,
+ const struct rfkill_event *event,
+ struct udev_device **ret) {
- r = mkdir_p("/var/lib/systemd/rfkill", 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create rfkill directory: %m");
- return EXIT_FAILURE;
- }
+ _cleanup_free_ char *sysname = NULL;
+ struct udev_device *device;
+ const char *name;
- udev = udev_new();
- if (!udev) {
- log_oom();
- return EXIT_FAILURE;
- }
+ assert(udev);
+ assert(event);
+ assert(ret);
- device = udev_device_new_from_subsystem_sysname(udev, "rfkill", argv[2]);
- if (!device) {
- log_debug_errno(errno, "Failed to get rfkill device '%s', ignoring: %m", argv[2]);
- return EXIT_SUCCESS;
- }
+ if (asprintf(&sysname, "rfkill%i", event->idx) < 0)
+ return log_oom();
+
+ device = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
+ if (!device)
+ return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m");
name = udev_device_get_sysattr_value(device, "name");
if (!name) {
- log_error("rfkill device has no name? Ignoring device.");
- return EXIT_SUCCESS;
+ log_debug("Device has no name, ignoring.");
+ udev_device_unref(device);
+ return -ENOENT;
}
log_debug("Operating on rfkill device '%s'.", name);
- type = udev_device_get_sysattr_value(device, "type");
- if (!type) {
- log_error("rfkill device has no type? Ignoring device.");
- return EXIT_SUCCESS;
+ *ret = device;
+ return 0;
+}
+
+static int wait_for_initialized(
+ struct udev *udev,
+ struct udev_device *device,
+ struct udev_device **ret) {
+
+ _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL;
+ struct udev_device *d;
+ const char *sysname;
+ int watch_fd, r;
+
+ assert(udev);
+ assert(device);
+ assert(ret);
+
+ if (udev_device_get_is_initialized(device) != 0) {
+ *ret = udev_device_ref(device);
+ return 0;
}
- escaped_type = cescape(type);
- if (!escaped_type) {
- log_oom();
- return EXIT_FAILURE;
+ assert_se(sysname = udev_device_get_sysname(device));
+
+ /* Wait until the device is initialized, so that we can get
+ * access to the ID_PATH property */
+
+ monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (!monitor)
+ return log_error_errno(errno, "Failed to acquire monitor: %m");
+
+ r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add rfkill udev match to monitor: %m");
+
+ r = udev_monitor_enable_receiving(monitor);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enable udev receiving: %m");
+
+ watch_fd = udev_monitor_get_fd(monitor);
+ if (watch_fd < 0)
+ return log_error_errno(watch_fd, "Failed to get watch fd: %m");
+
+ /* Check again, maybe things changed */
+ d = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname);
+ if (!d)
+ return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m");
+
+ if (udev_device_get_is_initialized(d) != 0) {
+ *ret = d;
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_udev_device_unref_ struct udev_device *t = NULL;
+
+ r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
+ if (r == -EINTR)
+ continue;
+ if (r < 0)
+ return log_error_errno(r, "Failed to watch udev monitor: %m");
+
+ t = udev_monitor_receive_device(monitor);
+ if (!t)
+ continue;
+
+ if (streq_ptr(udev_device_get_sysname(device), sysname)) {
+ *ret = udev_device_ref(t);
+ return 0;
+ }
}
+}
+
+static int determine_state_file(
+ struct udev *udev,
+ const struct rfkill_event *event,
+ struct udev_device *d,
+ char **ret) {
+
+ _cleanup_udev_device_unref_ struct udev_device *device = NULL;
+ const char *path_id, *type;
+ char *state_file;
+ int r;
+
+ assert(event);
+ assert(d);
+ assert(ret);
+
+ r = wait_for_initialized(udev, d, &device);
+ if (r < 0)
+ return r;
+
+ assert_se(type = rfkill_type_to_string(event->type));
path_id = udev_device_get_property_value(device, "ID_PATH");
if (path_id) {
+ _cleanup_free_ char *escaped_path_id = NULL;
+
escaped_path_id = cescape(path_id);
- if (!escaped_path_id) {
- log_oom();
- return EXIT_FAILURE;
- }
+ if (!escaped_path_id)
+ return log_oom();
- saved = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", escaped_type, NULL);
+ state_file = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", type, NULL);
} else
- saved = strjoin("/var/lib/systemd/rfkill/", escaped_type, NULL);
+ state_file = strjoin("/var/lib/systemd/rfkill/", type, NULL);
+
+ if (!state_file)
+ return log_oom();
+
+ *ret = state_file;
+ return 0;
+}
+
+static int load_state(
+ int rfkill_fd,
+ struct udev *udev,
+ const struct rfkill_event *event) {
+
+ _cleanup_udev_device_unref_ struct udev_device *device = NULL;
+ _cleanup_free_ char *state_file = NULL, *value = NULL;
+ struct rfkill_event we;
+ ssize_t l;
+ int b, r;
- if (!saved) {
- log_oom();
+ assert(rfkill_fd >= 0);
+ assert(udev);
+ assert(event);
+
+ if (!shall_restore_state())
+ return 0;
+
+ r = find_device(udev, event, &device);
+ if (r < 0)
+ return r;
+
+ r = determine_state_file(udev, event, device, &state_file);
+ if (r < 0)
+ return r;
+
+ r = read_one_line_file(state_file, &value);
+ if (r == -ENOENT) {
+ /* No state file? Then save the current state */
+
+ r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write state file %s: %m", state_file);
+
+ log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
+ return 0;
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to read state file %s: %m", state_file);
+
+ b = parse_boolean(value);
+ if (b < 0)
+ return log_error_errno(b, "Failed to parse state file %s: %m", state_file);
+
+ we = (struct rfkill_event) {
+ .op = RFKILL_OP_CHANGE,
+ .idx = event->idx,
+ .soft = b,
+ };
+
+ l = write(rfkill_fd, &we, sizeof(we));
+ if (l < 0)
+ return log_error_errno(errno, "Failed to restore rfkill state for %i: %m", event->idx);
+ if (l != sizeof(we)) {
+ log_error("Couldn't write rfkill event structure, too short.");
+ return -EIO;
+ }
+
+ log_debug("Loaded state '%s' from %s.", one_zero(b), state_file);
+ return 0;
+}
+
+static int save_state(
+ int rfkill_fd,
+ struct udev *udev,
+ const struct rfkill_event *event) {
+
+ _cleanup_udev_device_unref_ struct udev_device *device = NULL;
+ _cleanup_free_ char *state_file = NULL;
+ int r;
+
+ assert(rfkill_fd >= 0);
+ assert(udev);
+ assert(event);
+
+ r = find_device(udev, event, &device);
+ if (r < 0)
+ return r;
+
+ r = determine_state_file(udev, event, device, &state_file);
+ if (r < 0)
+ return r;
+
+ r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write state file %s: %m", state_file);
+
+ log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file);
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ _cleanup_udev_unref_ struct udev *udev = NULL;
+ _cleanup_close_ int rfkill_fd = -1;
+ bool ready = false;
+ int r, n;
+
+ if (argc > 1) {
+ log_error("This program requires no arguments.");
return EXIT_FAILURE;
}
- if (streq(argv[1], "load")) {
- _cleanup_free_ char *value = NULL;
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
- if (!shall_restore_state())
- return EXIT_SUCCESS;
+ umask(0022);
- r = read_one_line_file(saved, &value);
- if (r == -ENOENT)
- return EXIT_SUCCESS;
- if (r < 0) {
- log_error_errno(r, "Failed to read %s: %m", saved);
- return EXIT_FAILURE;
+ udev = udev_new();
+ if (!udev) {
+ r = log_oom();
+ goto finish;
+ }
+
+ r = mkdir_p("/var/lib/systemd/rfkill", 0755);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create rfkill directory: %m");
+ goto finish;
+ }
+
+ n = sd_listen_fds(false);
+ if (n < 0) {
+ r = log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m");
+ goto finish;
+ }
+ if (n > 1) {
+ log_error("Got too many file descriptors.");
+ r = -EINVAL;
+ goto finish;
+ }
+
+ if (n == 0) {
+ rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+ if (rfkill_fd < 0) {
+ if (errno == ENOENT) {
+ log_debug_errno(errno, "Missing rfkill subsystem, or no device present, exiting.");
+ r = 0;
+ goto finish;
+ }
+
+ r = log_error_errno(errno, "Failed to open /dev/rfkill: %m");
+ goto finish;
}
+ } else {
+ rfkill_fd = SD_LISTEN_FDS_START;
- r = udev_device_set_sysattr_value(device, "soft", value);
+ r = fd_nonblock(rfkill_fd, 1);
if (r < 0) {
- log_debug_errno(r, "Failed to write 'soft' attribute on rfkill device, ignoring: %m");
- return EXIT_SUCCESS;
+ log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m");
+ goto finish;
}
+ }
+
+ for (;;) {
+ struct rfkill_event event;
+ const char *type;
+ ssize_t l;
- } else if (streq(argv[1], "save")) {
- const char *value;
+ l = read(rfkill_fd, &event, sizeof(event));
+ if (l < 0) {
+ if (errno == EAGAIN) {
- value = udev_device_get_sysattr_value(device, "soft");
- if (!value) {
- log_debug_errno(r, "Failed to read system attribute, ignoring device: %m");
- return EXIT_SUCCESS;
+ if (!ready) {
+ /* Notify manager that we are
+ * now finished with
+ * processing whatever was
+ * queued */
+ (void) sd_notify(false, "READY=1");
+ ready = true;
+ }
+
+ /* Hang around for a bit, maybe there's more coming */
+
+ r = fd_wait_for_event(rfkill_fd, POLLIN, EXIT_USEC);
+ if (r == -EINTR)
+ continue;
+ if (r < 0) {
+ log_error_errno(r, "Failed to poll() on device: %m");
+ goto finish;
+ }
+ if (r > 0)
+ continue;
+
+ log_debug("All events read and idle, exiting.");
+ break;
+ }
+
+ log_error_errno(errno, "Failed to read from /dev/rfkill: %m");
}
- r = write_string_file(saved, value, WRITE_STRING_FILE_CREATE);
- if (r < 0) {
- log_error_errno(r, "Failed to write %s: %m", saved);
- return EXIT_FAILURE;
+ if (l != RFKILL_EVENT_SIZE_V1) {
+ log_error("Read event structure of invalid size.");
+ r = -EIO;
+ goto finish;
}
- } else {
- log_error("Unknown verb %s.", argv[1]);
- return EXIT_FAILURE;
+ type = rfkill_type_to_string(event.type);
+ if (!type) {
+ log_debug("An rfkill device of unknown type %i discovered, ignoring.", event.type);
+ continue;
+ }
+
+ switch (event.op) {
+
+ case RFKILL_OP_ADD:
+ log_debug("A new rfkill device has been added with index %i and type %s.", event.idx, type);
+ (void) load_state(rfkill_fd, udev, &event);
+ break;
+
+ case RFKILL_OP_DEL:
+ log_debug("An rfkill device has been removed with index %i and type %s", event.idx, type);
+ break;
+
+ case RFKILL_OP_CHANGE:
+ log_debug("An rfkill device has changed state with index %i and type %s", event.idx, type);
+ (void) save_state(rfkill_fd, udev, &event);
+ break;
+
+ default:
+ log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event.op, event.idx, type);
+ break;
+ }
}
- return EXIT_SUCCESS;
+ r = 0;
+
+finish:
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/run/run.c b/src/run/run.c
index 657c6fcaf1..93d8cd1d08 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -19,24 +19,25 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <getopt.h>
+#include <stdio.h>
#include "sd-bus.h"
#include "sd-event.h"
+
+#include "bus-error.h"
#include "bus-util.h"
-#include "event-util.h"
-#include "strv.h"
-#include "build.h"
-#include "unit-name.h"
+#include "calendarspec.h"
#include "env-util.h"
+#include "event-util.h"
+#include "formats-util.h"
#include "path-util.h"
-#include "bus-error.h"
-#include "calendarspec.h"
#include "ptyfwd.h"
-#include "formats-util.h"
#include "signal-util.h"
#include "spawn-polkit-agent.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "unit-name.h"
static bool arg_ask_password = true;
static bool arg_scope = false;
@@ -62,7 +63,7 @@ static usec_t arg_on_boot = 0;
static usec_t arg_on_startup = 0;
static usec_t arg_on_unit_active = 0;
static usec_t arg_on_unit_inactive = 0;
-static char *arg_on_calendar = NULL;
+static const char *arg_on_calendar = NULL;
static char **arg_timer_property = NULL;
static bool arg_quiet = false;
@@ -181,7 +182,6 @@ static int parse_argv(int argc, char *argv[]) {
};
int r, c;
- CalendarSpec *spec = NULL;
assert(argc >= 0);
assert(argv);
@@ -199,9 +199,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_USER:
arg_user = true;
@@ -337,16 +335,19 @@ static int parse_argv(int argc, char *argv[]) {
break;
- case ARG_ON_CALENDAR:
+ case ARG_ON_CALENDAR: {
+ CalendarSpec *spec = NULL;
r = calendar_spec_from_string(optarg, &spec);
if (r < 0) {
log_error("Invalid calendar spec: %s", optarg);
return r;
}
- free(spec);
+
+ calendar_spec_free(spec);
arg_on_calendar = optarg;
break;
+ }
case ARG_TIMER_PROPERTY:
@@ -391,6 +392,11 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (arg_pty && arg_transport == BUS_TRANSPORT_REMOTE) {
+ log_error("--pty is only supported when connecting to the local system or containers.");
+ return -EINVAL;
+ }
+
if (arg_scope && with_timer()) {
log_error("Timer options are not supported in --scope mode.");
return -EINVAL;
@@ -709,9 +715,9 @@ static int start_transient_service(
_cleanup_bus_unref_ sd_bus *system_bus = NULL;
const char *s;
- r = sd_bus_open_system(&system_bus);
+ r = sd_bus_default_system(&system_bus);
if (r < 0)
- log_error_errno(r, "Failed to connect to system bus: %m");
+ return log_error_errno(r, "Failed to connect to system bus: %m");
r = sd_bus_call_method(system_bus,
"org.freedesktop.machine1",
@@ -796,10 +802,8 @@ static int start_transient_service(
polkit_agent_open_if_enabled();
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to start transient service unit: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to start transient service unit: %s", bus_error_message(&error, r));
if (w) {
const char *object;
@@ -830,7 +834,7 @@ static int start_transient_service(
if (!arg_quiet)
log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service);
- r = pty_forward_new(event, master, false, false, &forward);
+ r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");
@@ -1176,7 +1180,7 @@ int main(int argc, char* argv[]) {
arg_description = description;
}
- r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus);
+ r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
diff --git a/src/shared/architecture.h b/src/shared/architecture.h
index f5bbf65a90..61d067cad7 100644
--- a/src/shared/architecture.h
+++ b/src/shared/architecture.h
@@ -78,9 +78,11 @@ int uname_architecture(void);
#if defined(__x86_64__)
# define native_architecture() ARCHITECTURE_X86_64
# define LIB_ARCH_TUPLE "x86_64-linux-gnu"
+# define PROC_CPUINFO_MODEL "model name"
#elif defined(__i386__)
# define native_architecture() ARCHITECTURE_X86
# define LIB_ARCH_TUPLE "i386-linux-gnu"
+# define PROC_CPUINFO_MODEL "model name"
#elif defined(__powerpc64__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_PPC64
@@ -89,6 +91,7 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_PPC64_LE
# define LIB_ARCH_TUPLE "powerpc64le-linux-gnu"
# endif
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__powerpc__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_PPC
@@ -97,15 +100,18 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_PPC_LE
# error "Missing LIB_ARCH_TUPLE for PPCLE"
# endif
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__ia64__)
# define native_architecture() ARCHITECTURE_IA64
# define LIB_ARCH_TUPLE "ia64-linux-gnu"
#elif defined(__hppa64__)
# define native_architecture() ARCHITECTURE_PARISC64
# error "Missing LIB_ARCH_TUPLE for HPPA64"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__hppa__)
# define native_architecture() ARCHITECTURE_PARISC
# define LIB_ARCH_TUPLE "hppa‑linux‑gnu"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__s390x__)
# define native_architecture() ARCHITECTURE_S390X
# define LIB_ARCH_TUPLE "s390x-linux-gnu"
@@ -115,9 +121,11 @@ int uname_architecture(void);
#elif defined(__sparc64__)
# define native_architecture() ARCHITECTURE_SPARC64
# define LIB_ARCH_TUPLE "sparc64-linux-gnu"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__sparc__)
# define native_architecture() ARCHITECTURE_SPARC
# define LIB_ARCH_TUPLE "sparc-linux-gnu"
+# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__mips64__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_MIPS64
@@ -126,6 +134,7 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_MIPS64_LE
# error "Missing LIB_ARCH_TUPLE for MIPS64_LE"
# endif
+# define PROC_CPUINFO_MODEL "cpu model"
#elif defined(__mips__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_MIPS
@@ -134,6 +143,7 @@ int uname_architecture(void);
# define native_architecture() ARCHITECTURE_MIPS_LE
# define LIB_ARCH_TUPLE "mipsel-linux-gnu"
# endif
+# define PROC_CPUINFO_MODEL "cpu model"
#elif defined(__alpha__)
# define native_architecture() ARCHITECTURE_ALPHA
# define LIB_ARCH_TUPLE "alpha-linux-gnu"
@@ -169,6 +179,7 @@ int uname_architecture(void);
# define LIB_ARCH_TUPLE "arm-linux-gnu"
# endif
# endif
+# define PROC_CPUINFO_MODEL "model name"
#elif defined(__sh64__)
# define native_architecture() ARCHITECTURE_SH64
# error "Missing LIB_ARCH_TUPLE for SH64"
@@ -188,5 +199,10 @@ int uname_architecture(void);
# error "Please register your architecture here!"
#endif
+#ifndef PROC_CPUINFO_MODEL
+#warning "PROC_CPUINFO_MODEL not defined for your architecture"
+#define PROC_CPUINFO_MODEL "model name"
+#endif
+
const char *architecture_to_string(int a) _const_;
int architecture_from_string(const char *s) _pure_;
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index f5cff6fc56..f8cf11b297 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -18,28 +18,158 @@
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
-#include <termios.h>
-#include <unistd.h>
-#include <poll.h>
-#include <sys/inotify.h>
+
#include <errno.h>
#include <fcntl.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <sys/un.h>
+#include <poll.h>
+#include <stdbool.h>
#include <stddef.h>
+#include <string.h>
+#include <sys/inotify.h>
#include <sys/signalfd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <termios.h>
+#include <unistd.h>
-#include "util.h"
#include "formats-util.h"
+#include "missing.h"
#include "mkdir.h"
-#include "strv.h"
#include "random-util.h"
-#include "terminal-util.h"
#include "signal-util.h"
+#include "socket-util.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "util.h"
#include "ask-password-api.h"
+#define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
+
+static int lookup_key(const char *keyname, key_serial_t *ret) {
+ key_serial_t serial;
+
+ assert(keyname);
+ assert(ret);
+
+ serial = request_key("user", keyname, NULL, 0);
+ if (serial == -1)
+ return -errno;
+
+ *ret = serial;
+ return 0;
+}
+
+static int retrieve_key(key_serial_t serial, char ***ret) {
+ _cleanup_free_ char *p = NULL;
+ long m = 100, n;
+ char **l;
+
+ assert(ret);
+
+ for (;;) {
+ p = new(char, m);
+ if (!p)
+ return -ENOMEM;
+
+ n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
+ if (n < 0)
+ return -errno;
+
+ if (n < m)
+ break;
+
+ free(p);
+ m *= 2;
+ }
+
+ l = strv_parse_nulstr(p, n);
+ if (!l)
+ return -ENOMEM;
+
+ *ret = l;
+ return 0;
+}
+
+static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) {
+ _cleanup_strv_free_ char **l = NULL;
+ _cleanup_free_ char *p = NULL;
+ key_serial_t serial;
+ size_t n;
+ int r;
+
+ assert(keyname);
+ assert(passwords);
+
+ if (!(flags & ASK_PASSWORD_PUSH_CACHE))
+ return 0;
+
+ r = lookup_key(keyname, &serial);
+ if (r >= 0) {
+ r = retrieve_key(serial, &l);
+ if (r < 0)
+ return r;
+ } else if (r != -ENOKEY)
+ return r;
+
+ r = strv_extend_strv(&l, passwords, true);
+ if (r <= 0)
+ return r;
+
+ r = strv_make_nulstr(l, &p, &n);
+ if (r < 0)
+ return r;
+
+ /* Truncate trailing NUL */
+ assert(n > 0);
+ assert(p[n-1] == 0);
+
+ serial = add_key("user", keyname, p, n-1, KEY_SPEC_USER_KEYRING);
+ if (serial == -1)
+ return -errno;
+
+ if (keyctl(KEYCTL_SET_TIMEOUT,
+ (unsigned long) serial,
+ (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0)
+ log_debug_errno(errno, "Failed to adjust timeout: %m");
+
+ log_debug("Added key to keyring as %" PRIi32 ".", serial);
+
+ return 1;
+}
+
+static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) {
+ int r;
+
+ assert(keyname);
+ assert(passwords);
+
+ r = add_to_keyring(keyname, flags, passwords);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to add password to keyring: %m");
+
+ return 0;
+}
+
+int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) {
+
+ key_serial_t serial;
+ int r;
+
+ assert(keyname);
+ assert(ret);
+
+ if (!(flags & ASK_PASSWORD_ACCEPT_CACHED))
+ return -EUNATCH;
+
+ r = lookup_key(keyname, &serial);
+ if (r == -ENOSYS) /* when retrieving the distinction doesn't matter */
+ return -ENOKEY;
+ if (r < 0)
+ return r;
+
+ return retrieve_key(serial, ret);
+}
+
static void backspace_chars(int ttyfd, size_t p) {
if (ttyfd < 0)
@@ -54,10 +184,11 @@ static void backspace_chars(int ttyfd, size_t p) {
int ask_password_tty(
const char *message,
+ const char *keyname,
usec_t until,
- bool echo,
+ AskPasswordFlags flags,
const char *flag_file,
- char **_passphrase) {
+ char **ret) {
struct termios old_termios, new_termios;
char passphrase[LINE_MAX], *x;
@@ -66,15 +197,19 @@ int ask_password_tty(
_cleanup_close_ int ttyfd = -1, notify = -1;
struct pollfd pollfd[2];
bool reset_tty = false;
- bool silent_mode = false;
bool dirty = false;
enum {
POLL_TTY,
POLL_INOTIFY
};
- assert(message);
- assert(_passphrase);
+ assert(ret);
+
+ if (flags & ASK_PASSWORD_NO_TTY)
+ return -EUNATCH;
+
+ if (!message)
+ message = "Password:";
if (flag_file) {
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
@@ -97,10 +232,10 @@ int ask_password_tty(
goto finish;
}
- loop_write(ttyfd, ANSI_HIGHLIGHT_ON, sizeof(ANSI_HIGHLIGHT_ON)-1, false);
+ loop_write(ttyfd, ANSI_HIGHLIGHT, strlen(ANSI_HIGHLIGHT), false);
loop_write(ttyfd, message, strlen(message), false);
loop_write(ttyfd, " ", 1, false);
- loop_write(ttyfd, ANSI_HIGHLIGHT_OFF, sizeof(ANSI_HIGHLIGHT_OFF)-1, false);
+ loop_write(ttyfd, ANSI_NORMAL, strlen(ANSI_NORMAL), false);
new_termios = old_termios;
new_termios.c_lflag &= ~(ICANON|ECHO);
@@ -145,7 +280,7 @@ int ask_password_tty(
goto finish;
}
- k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for);
+ k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
if (k < 0) {
if (errno == EINTR)
continue;
@@ -157,7 +292,7 @@ int ask_password_tty(
goto finish;
}
- if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
+ if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
flush_fd(notify);
if (pollfd[POLL_TTY].revents == 0)
@@ -178,7 +313,7 @@ int ask_password_tty(
break;
else if (c == 21) { /* C-u */
- if (!silent_mode)
+ if (!(flags & ASK_PASSWORD_SILENT))
backspace_chars(ttyfd, p);
p = 0;
@@ -186,28 +321,28 @@ int ask_password_tty(
if (p > 0) {
- if (!silent_mode)
+ if (!(flags & ASK_PASSWORD_SILENT))
backspace_chars(ttyfd, 1);
p--;
- } else if (!dirty && !silent_mode) {
+ } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
- silent_mode = true;
+ flags |= ASK_PASSWORD_SILENT;
/* There are two ways to enter silent
* mode. Either by pressing backspace
- * as first key (and only as first key),
- * or ... */
+ * as first key (and only as first
+ * key), or ... */
if (ttyfd >= 0)
loop_write(ttyfd, "(no echo) ", 10, false);
} else if (ttyfd >= 0)
loop_write(ttyfd, "\a", 1, false);
- } else if (c == '\t' && !silent_mode) {
+ } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
backspace_chars(ttyfd, p);
- silent_mode = true;
+ flags |= ASK_PASSWORD_SILENT;
/* ... or by pressing TAB at any time. */
@@ -221,8 +356,8 @@ int ask_password_tty(
passphrase[p++] = c;
- if (!silent_mode && ttyfd >= 0)
- loop_write(ttyfd, echo ? &c : "*", 1, false);
+ if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0)
+ loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false);
dirty = true;
}
@@ -234,7 +369,10 @@ int ask_password_tty(
goto finish;
}
- *_passphrase = x;
+ if (keyname)
+ (void) add_to_keyring_and_log(keyname, flags, STRV_MAKE(x));
+
+ *ret = x;
r = 0;
finish:
@@ -247,52 +385,38 @@ finish:
}
static int create_socket(char **name) {
- int fd;
- union {
- struct sockaddr sa;
- struct sockaddr_un un;
- } sa = {
+ union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
- int one = 1;
- int r = 0;
+ _cleanup_close_ int fd = -1;
+ static const int one = 1;
char *c;
+ int r;
assert(name);
fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (fd < 0)
- return log_error_errno(errno, "socket() failed: %m");
+ return -errno;
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
RUN_WITH_UMASK(0177) {
- r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- }
-
- if (r < 0) {
- r = -errno;
- log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
- goto fail;
+ if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ return -errno;
}
- if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
- r = -errno;
- log_error_errno(errno, "SO_PASSCRED failed: %m");
- goto fail;
- }
+ if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
+ return -errno;
c = strdup(sa.un.sun_path);
- if (!c) {
- r = log_oom();
- goto fail;
- }
+ if (!c)
+ return -ENOMEM;
*name = c;
- return fd;
-fail:
- safe_close(fd);
+ r = fd;
+ fd = -1;
return r;
}
@@ -301,10 +425,10 @@ int ask_password_agent(
const char *message,
const char *icon,
const char *id,
+ const char *keyname,
usec_t until,
- bool echo,
- bool accept_cached,
- char ***_passphrases) {
+ AskPasswordFlags flags,
+ char ***ret) {
enum {
FD_SOCKET,
@@ -312,35 +436,38 @@ int ask_password_agent(
_FD_MAX
};
+ _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1;
char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
char final[sizeof(temp)] = "";
- _cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *socket_name = NULL;
- _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1;
- sigset_t mask, oldmask;
+ _cleanup_strv_free_ char **l = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
struct pollfd pollfd[_FD_MAX];
+ sigset_t mask, oldmask;
int r;
- assert(_passphrases);
+ assert(ret);
+
+ if (flags & ASK_PASSWORD_NO_AGENT)
+ return -EUNATCH;
assert_se(sigemptyset(&mask) >= 0);
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0);
- mkdir_p_label("/run/systemd/ask-password", 0755);
+ (void) mkdir_p_label("/run/systemd/ask-password", 0755);
fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC);
if (fd < 0) {
- r = log_error_errno(errno,
- "Failed to create password file: %m");
+ r = -errno;
goto finish;
}
- fchmod(fd, 0644);
+ (void) fchmod(fd, 0644);
f = fdopen(fd, "w");
if (!f) {
- r = log_error_errno(errno, "Failed to allocate FILE: %m");
+ r = -errno;
goto finish;
}
@@ -348,7 +475,7 @@ int ask_password_agent(
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (signal_fd < 0) {
- r = log_error_errno(errno, "signalfd(): %m");
+ r = -errno;
goto finish;
}
@@ -367,8 +494,8 @@ int ask_password_agent(
"NotAfter="USEC_FMT"\n",
getpid(),
socket_name,
- accept_cached ? 1 : 0,
- echo ? 1 : 0,
+ (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0,
+ (flags & ASK_PASSWORD_ECHO) ? 1 : 0,
until);
if (message)
@@ -381,10 +508,8 @@ int ask_password_agent(
fprintf(f, "Id=%s\n", id);
r = fflush_and_check(f);
- if (r < 0) {
- log_error_errno(r, "Failed to write query file: %m");
+ if (r < 0)
goto finish;
- }
memcpy(final, temp, sizeof(temp));
@@ -393,7 +518,7 @@ int ask_password_agent(
final[sizeof(final)-9] = 'k';
if (rename(temp, final) < 0) {
- r = log_error_errno(errno, "Failed to rename query file: %m");
+ r = -errno;
goto finish;
}
@@ -419,7 +544,6 @@ int ask_password_agent(
t = now(CLOCK_MONOTONIC);
if (until > 0 && until <= t) {
- log_notice("Timed out");
r = -ETIME;
goto finish;
}
@@ -429,12 +553,11 @@ int ask_password_agent(
if (errno == EINTR)
continue;
- r = log_error_errno(errno, "poll() failed: %m");
+ r = -errno;
goto finish;
}
if (k <= 0) {
- log_notice("Timed out");
r = -ETIME;
goto finish;
}
@@ -445,7 +568,6 @@ int ask_password_agent(
}
if (pollfd[FD_SOCKET].revents != POLLIN) {
- log_error("Unexpected poll() event.");
r = -EIO;
goto finish;
}
@@ -467,14 +589,14 @@ int ask_password_agent(
errno == EINTR)
continue;
- r = log_error_errno(errno, "recvmsg() failed: %m");
+ r = -errno;
goto finish;
}
cmsg_close_all(&msghdr);
if (n <= 0) {
- log_error("Message too short");
+ log_debug("Message too short");
continue;
}
@@ -482,84 +604,100 @@ int ask_password_agent(
control.cmsghdr.cmsg_level != SOL_SOCKET ||
control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
- log_warning("Received message without credentials. Ignoring.");
+ log_debug("Received message without credentials. Ignoring.");
continue;
}
ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
if (ucred->uid != 0) {
- log_warning("Got request from unprivileged user. Ignoring.");
+ log_debug("Got request from unprivileged user. Ignoring.");
continue;
}
if (passphrase[0] == '+') {
- char **l;
-
+ /* An empty message refers to the empty password */
if (n == 1)
l = strv_new("", NULL);
else
l = strv_parse_nulstr(passphrase+1, n-1);
- /* An empty message refers to the empty password */
-
if (!l) {
r = -ENOMEM;
goto finish;
}
if (strv_length(l) <= 0) {
- strv_free(l);
- log_error("Invalid packet");
+ l = strv_free(l);
+ log_debug("Invalid packet");
continue;
}
- *_passphrases = l;
+ break;
+ }
- } else if (passphrase[0] == '-') {
+ if (passphrase[0] == '-') {
r = -ECANCELED;
goto finish;
- } else {
- log_error("Invalid packet");
- continue;
}
- break;
+ log_debug("Invalid packet");
}
+ if (keyname)
+ (void) add_to_keyring_and_log(keyname, flags, l);
+
+ *ret = l;
+ l = NULL;
r = 0;
finish:
if (socket_name)
- unlink(socket_name);
+ (void) unlink(socket_name);
- unlink(temp);
+ (void) unlink(temp);
if (final[0])
- unlink(final);
+ (void) unlink(final);
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
-
return r;
}
-int ask_password_auto(const char *message, const char *icon, const char *id,
- usec_t until, bool accept_cached, char ***_passphrases) {
- assert(message);
- assert(_passphrases);
+int ask_password_auto(
+ const char *message,
+ const char *icon,
+ const char *id,
+ const char *keyname,
+ usec_t until,
+ AskPasswordFlags flags,
+ char ***ret) {
- if (isatty(STDIN_FILENO)) {
- int r;
+ int r;
+
+ assert(ret);
+
+ if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) {
+ r = ask_password_keyring(keyname, flags, ret);
+ if (r != -ENOKEY)
+ return r;
+ }
+
+ if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) {
char *s = NULL, **l = NULL;
- r = ask_password_tty(message, until, false, NULL, &s);
+ r = ask_password_tty(message, keyname, until, flags, NULL, &s);
if (r < 0)
return r;
r = strv_consume(&l, s);
if (r < 0)
- return r;
+ return -ENOMEM;
- *_passphrases = l;
- return r;
- } else
- return ask_password_agent(message, icon, id, until, false, accept_cached, _passphrases);
+ *ret = l;
+ return 0;
+ }
+
+ if (!(flags & ASK_PASSWORD_NO_AGENT))
+ return ask_password_agent(message, icon, id, keyname, until, flags, ret);
+
+ return -EUNATCH;
}
diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h
index 0954e072be..913cad9f8a 100644
--- a/src/shared/ask-password-api.h
+++ b/src/shared/ask-password-api.h
@@ -21,11 +21,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
-int ask_password_tty(const char *message, usec_t until, bool echo, const char *flag_file, char **_passphrase);
-
-int ask_password_agent(const char *message, const char *icon, const char *id,
- usec_t until, bool echo, bool accept_cached, char ***_passphrases);
-
-int ask_password_auto(const char *message, const char *icon, const char *id,
- usec_t until, bool accept_cached, char ***_passphrases);
+#include <stdbool.h>
+
+#include "time-util.h"
+
+typedef enum AskPasswordFlags {
+ ASK_PASSWORD_ACCEPT_CACHED = 1,
+ ASK_PASSWORD_PUSH_CACHE = 2,
+ ASK_PASSWORD_ECHO = 4, /* show the password literally while reading, instead of "*" */
+ ASK_PASSWORD_SILENT = 8, /* do no show any password at all while reading */
+ ASK_PASSWORD_NO_TTY = 16,
+ ASK_PASSWORD_NO_AGENT = 32,
+} AskPasswordFlags;
+
+int ask_password_tty(const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char **ret);
+int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
+int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret);
+int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c
index ab6fc171b0..48492ed13d 100644
--- a/src/shared/base-filesystem.c
+++ b/src/shared/base-filesystem.c
@@ -34,12 +34,13 @@ typedef struct BaseFilesystem {
mode_t mode;
const char *target;
const char *exists;
+ bool ignore_failure;
} BaseFilesystem;
static const BaseFilesystem table[] = {
{ "bin", 0, "usr/bin\0", NULL },
{ "lib", 0, "usr/lib\0", NULL },
- { "root", 0755, NULL, NULL },
+ { "root", 0755, NULL, NULL, true },
{ "sbin", 0, "usr/sbin\0", NULL },
{ "usr", 0755, NULL, NULL },
{ "var", 0755, NULL, NULL },
@@ -104,8 +105,13 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
RUN_WITH_UMASK(0000)
r = mkdirat(fd, table[i].dir, table[i].mode);
- if (r < 0 && errno != EEXIST)
- return log_error_errno(errno, "Failed to create directory at %s/%s: %m", root, table[i].dir);
+ if (r < 0 && errno != EEXIST) {
+ log_full_errno(table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno,
+ "Failed to create directory at %s/%s: %m", root, table[i].dir);
+
+ if (!table[i].ignore_failure)
+ return -errno;
+ }
if (uid != UID_INVALID || gid != UID_INVALID) {
if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 64a810fc8f..a5d6edbba9 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -23,22 +23,24 @@
#include "sd-daemon.h"
#include "sd-event.h"
-#include "util.h"
-#include "strv.h"
-#include "macro.h"
+#include "sd-bus.h"
+
+#include "bus-error.h"
+#include "bus-internal.h"
+#include "bus-label.h"
+#include "bus-message.h"
+#include "cgroup-util.h"
#include "def.h"
-#include "path-util.h"
+#include "macro.h"
#include "missing.h"
+#include "path-util.h"
#include "set.h"
#include "signal-util.h"
+#include "strv.h"
#include "unit-name.h"
+#include "util.h"
-#include "sd-bus.h"
-#include "bus-error.h"
-#include "bus-label.h"
-#include "bus-message.h"
#include "bus-util.h"
-#include "bus-internal.h"
static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
sd_event *e = userdata;
@@ -572,14 +574,14 @@ int bus_check_peercred(sd_bus *c) {
return 1;
}
-int bus_open_system_systemd(sd_bus **_bus) {
+int bus_connect_system_systemd(sd_bus **_bus) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
int r;
assert(_bus);
if (geteuid() != 0)
- return sd_bus_open_system(_bus);
+ return sd_bus_default_system(_bus);
/* If we are root and kdbus is not available, then let's talk
* directly to the system instance, instead of going via the
@@ -614,7 +616,7 @@ int bus_open_system_systemd(sd_bus **_bus) {
r = sd_bus_start(bus);
if (r < 0)
- return sd_bus_open_system(_bus);
+ return sd_bus_default_system(_bus);
r = bus_check_peercred(bus);
if (r < 0)
@@ -626,7 +628,7 @@ int bus_open_system_systemd(sd_bus **_bus) {
return 0;
}
-int bus_open_user_systemd(sd_bus **_bus) {
+int bus_connect_user_systemd(sd_bus **_bus) {
_cleanup_bus_unref_ sd_bus *bus = NULL;
_cleanup_free_ char *ee = NULL;
const char *e;
@@ -656,7 +658,7 @@ int bus_open_user_systemd(sd_bus **_bus) {
e = secure_getenv("XDG_RUNTIME_DIR");
if (!e)
- return sd_bus_open_user(_bus);
+ return sd_bus_default_user(_bus);
ee = bus_address_escape(e);
if (!ee)
@@ -672,7 +674,7 @@ int bus_open_user_systemd(sd_bus **_bus) {
r = sd_bus_start(bus);
if (r < 0)
- return sd_bus_open_user(_bus);
+ return sd_bus_default_user(_bus);
r = bus_check_peercred(bus);
if (r < 0)
@@ -1207,7 +1209,7 @@ int bus_map_all_properties(
return bus_message_map_all_properties(m, map, userdata);
}
-int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
+int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) {
int r;
assert(transport >= 0);
@@ -1242,7 +1244,7 @@ int bus_open_transport(BusTransport transport, const char *host, bool user, sd_b
return r;
}
-int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
+int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) {
int r;
assert(transport >= 0);
@@ -1256,9 +1258,9 @@ int bus_open_transport_systemd(BusTransport transport, const char *host, bool us
case BUS_TRANSPORT_LOCAL:
if (user)
- r = bus_open_user_systemd(bus);
+ r = bus_connect_user_systemd(bus);
else
- r = bus_open_system_systemd(bus);
+ r = bus_connect_system_systemd(bus);
break;
@@ -1421,9 +1423,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return bus_log_create_error(r);
if (STR_IN_SET(field,
- "CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
+ "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
- "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit")) {
+ "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
+ "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
+ "SyslogLevelPrefix")) {
r = parse_boolean(eq);
if (r < 0) {
@@ -1436,18 +1440,48 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
} else if (streq(field, "MemoryLimit")) {
uint64_t bytes;
- r = parse_size(eq, 1024, &bytes);
+ if (isempty(eq) || streq(eq, "infinity"))
+ bytes = (uint64_t) -1;
+ else {
+ r = parse_size(eq, 1024, &bytes);
+ if (r < 0) {
+ log_error("Failed to parse bytes specification %s", assignment);
+ return -EINVAL;
+ }
+ }
+
+ r = sd_bus_message_append(m, "v", "t", bytes);
+
+ } else if (streq(field, "TasksMax")) {
+ uint64_t n;
+
+ if (isempty(eq) || streq(eq, "infinity"))
+ n = (uint64_t) -1;
+ else {
+ r = safe_atou64(eq, &n);
+ if (r < 0) {
+ log_error("Failed to parse maximum tasks specification %s", assignment);
+ return -EINVAL;
+ }
+ }
+
+ r = sd_bus_message_append(m, "v", "t", n);
+
+ } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) {
+ uint64_t u;
+
+ r = cg_cpu_shares_parse(eq, &u);
if (r < 0) {
- log_error("Failed to parse bytes specification %s", assignment);
+ log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
- r = sd_bus_message_append(m, "v", "t", bytes);
+ r = sd_bus_message_append(m, "v", "t", u);
- } else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
+ } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
uint64_t u;
- r = safe_atou64(eq, &u);
+ r = cg_cpu_shares_parse(eq, &u);
if (r < 0) {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
@@ -1459,10 +1493,33 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"User", "Group", "DevicePolicy", "KillMode",
"UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
"StandardInput", "StandardOutput", "StandardError",
- "Description", "Slice", "Type"))
+ "Description", "Slice", "Type", "WorkingDirectory",
+ "RootDirectory", "SyslogIdentifier"))
r = sd_bus_message_append(m, "v", "s", eq);
- else if (streq(field, "DeviceAllow")) {
+ else if (streq(field, "SyslogLevel")) {
+ int level;
+
+ level = log_level_from_string(eq);
+ if (level < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", level);
+
+ } else if (streq(field, "SyslogFacility")) {
+ int facility;
+
+ facility = log_facility_unshifted_from_string(eq);
+ if (facility < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", facility);
+
+ } else if (streq(field, "DeviceAllow")) {
if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(ss)", 0);
@@ -1598,7 +1655,16 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
}
r = sd_bus_message_append(m, "v", "t", u);
+ } else if (streq(field, "TimerSlackNSec")) {
+ nsec_t n;
+ r = parse_nsec(eq, &n);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "t", n);
} else {
log_error("Unknown assignment %s.", assignment);
return -EINVAL;
@@ -2103,3 +2169,42 @@ bool is_kdbus_available(void) {
return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0;
}
+
+int bus_property_get_rlimit(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ struct rlimit *rl;
+ uint64_t u;
+ rlim_t x;
+
+ assert(bus);
+ assert(reply);
+ assert(userdata);
+
+ rl = *(struct rlimit**) userdata;
+ if (rl)
+ x = rl->rlim_max;
+ else {
+ struct rlimit buf = {};
+ int z;
+
+ z = rlimit_from_string(strstr(property, "Limit"));
+ assert(z >= 0);
+
+ getrlimit(z, &buf);
+ x = buf.rlim_max;
+ }
+
+ /* rlim_t might have different sizes, let's map
+ * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
+ * all archs */
+ u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
+
+ return sd_bus_message_append(reply, "t", u);
+}
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index d2b2d701ce..fd70842b9e 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -65,11 +65,11 @@ int bus_test_polkit(sd_bus_message *call, int capability, const char *action, co
int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error);
void bus_verify_polkit_async_registry_free(Hashmap *registry);
-int bus_open_system_systemd(sd_bus **_bus);
-int bus_open_user_systemd(sd_bus **_bus);
+int bus_connect_system_systemd(sd_bus **_bus);
+int bus_connect_user_systemd(sd_bus **_bus);
-int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
-int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
+int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
+int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
int bus_print_property(const char *name, sd_bus_message *property, bool all);
int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all);
@@ -200,3 +200,5 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send
bool is_kdbus_wanted(void);
bool is_kdbus_available(void);
+
+int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 946eac6823..c282fb1231 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -147,8 +147,7 @@ static int next_assignment(const char *unit,
/* Warn about unknown non-extension fields. */
if (!relaxed && !startswith(lvalue, "X-"))
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Unknown lvalue '%s' in section '%s'", lvalue, section);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
return 0;
}
@@ -196,8 +195,7 @@ static int parse_line(const char* unit,
* Support for them should be eventually removed. */
if (!allow_include) {
- log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
- ".include not allowed here. Ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
return 0;
}
@@ -216,8 +214,7 @@ static int parse_line(const char* unit,
assert(k > 0);
if (l[k-1] != ']') {
- log_syntax(unit, LOG_ERR, filename, line, EBADMSG,
- "Invalid section header '%s'", l);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l);
return -EBADMSG;
}
@@ -228,8 +225,7 @@ static int parse_line(const char* unit,
if (sections && !nulstr_contains(sections, n)) {
if (!relaxed && !startswith(n, "X-"))
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Unknown section '%s'. Ignoring.", n);
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
free(n);
*section = mfree(*section);
@@ -248,16 +244,15 @@ static int parse_line(const char* unit,
if (sections && !*section) {
if (!relaxed && !*section_ignored)
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Assignment outside of section. Ignoring.");
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
return 0;
}
e = strchr(l, '=');
if (!e) {
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='.");
- return -EBADMSG;
+ log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='.");
+ return -EINVAL;
}
*e = 0;
@@ -420,16 +415,17 @@ int config_parse_many(const char *conf_file,
}
#define DEFINE_PARSER(type, vartype, conv_func) \
- int config_parse_##type(const char *unit, \
- const char *filename, \
- unsigned line, \
- const char *section, \
- unsigned section_line, \
- const char *lvalue, \
- int ltype, \
- const char *rvalue, \
- void *data, \
- void *userdata) { \
+ int config_parse_##type( \
+ const char *unit, \
+ const char *filename, \
+ unsigned line, \
+ const char *section, \
+ unsigned section_line, \
+ const char *lvalue, \
+ int ltype, \
+ const char *rvalue, \
+ void *data, \
+ void *userdata) { \
\
vartype *i = data; \
int r; \
@@ -441,21 +437,23 @@ int config_parse_many(const char *conf_file,
\
r = conv_func(rvalue, i); \
if (r < 0) \
- log_syntax(unit, LOG_ERR, filename, line, -r, \
+ log_syntax(unit, LOG_ERR, filename, line, r, \
"Failed to parse %s value, ignoring: %s", \
#type, rvalue); \
\
return 0; \
- }
-
-DEFINE_PARSER(int, int, safe_atoi)
-DEFINE_PARSER(long, long, safe_atoli)
-DEFINE_PARSER(uint32, uint32_t, safe_atou32)
-DEFINE_PARSER(uint64, uint64_t, safe_atou64)
-DEFINE_PARSER(unsigned, unsigned, safe_atou)
-DEFINE_PARSER(double, double, safe_atod)
-DEFINE_PARSER(nsec, nsec_t, parse_nsec)
-DEFINE_PARSER(sec, usec_t, parse_sec)
+ } \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+DEFINE_PARSER(int, int, safe_atoi);
+DEFINE_PARSER(long, long, safe_atoli);
+DEFINE_PARSER(uint32, uint32_t, safe_atou32);
+DEFINE_PARSER(uint64, uint64_t, safe_atou64);
+DEFINE_PARSER(unsigned, unsigned, safe_atou);
+DEFINE_PARSER(double, double, safe_atod);
+DEFINE_PARSER(nsec, nsec_t, parse_nsec);
+DEFINE_PARSER(sec, usec_t, parse_sec);
+DEFINE_PARSER(mode, mode_t, parse_mode);
int config_parse_iec_size(const char* unit,
const char *filename,
@@ -479,7 +477,7 @@ int config_parse_iec_size(const char* unit,
r = parse_size(rvalue, 1024, &v);
if (r < 0 || (uint64_t) (size_t) v != v) {
- log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
@@ -509,7 +507,7 @@ int config_parse_si_size(const char* unit,
r = parse_size(rvalue, 1000, &v);
if (r < 0 || (uint64_t) (size_t) v != v) {
- log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue);
return 0;
}
@@ -564,8 +562,7 @@ int config_parse_bool(const char* unit,
k = parse_boolean(rvalue);
if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -k,
- "Failed to parse boolean value, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue);
return 0;
}
@@ -626,7 +623,7 @@ int config_parse_string(
assert(data);
if (!utf8_is_valid(rvalue)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return 0;
}
@@ -664,12 +661,12 @@ int config_parse_path(
assert(data);
if (!utf8_is_valid(rvalue)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
return 0;
}
if (!path_is_absolute(rvalue)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
return 0;
}
@@ -730,7 +727,7 @@ int config_parse_strv(const char *unit,
return log_oom();
if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
free(n);
continue;
}
@@ -740,35 +737,7 @@ int config_parse_strv(const char *unit,
return log_oom();
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-int config_parse_mode(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- mode_t *m = data;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (parse_mode(rvalue, m) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue);
- return 0;
- }
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -795,7 +764,7 @@ int config_parse_log_facility(
x = log_facility_unshifted_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue);
return 0;
}
@@ -826,7 +795,7 @@ int config_parse_log_level(
x = log_level_from_string(rvalue);
if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue);
return 0;
}
@@ -855,7 +824,7 @@ int config_parse_signal(
r = signal_from_string_try_harder(rvalue);
if (r <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse signal name, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue);
return 0;
}
@@ -884,7 +853,7 @@ int config_parse_personality(
p = personality_from_string(rvalue);
if (p == PERSONALITY_INVALID) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse personality, ignoring: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue);
return 0;
}
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 4efed138c9..fb0234baae 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -123,13 +123,6 @@ int config_parse_log_level(const char *unit, const char *filename, unsigned line
int config_parse_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_personality(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-#define log_invalid_utf8(unit, level, config_file, config_line, error, rvalue) \
- do { \
- _cleanup_free_ char *_p = utf8_escape_invalid(rvalue); \
- log_syntax(unit, level, config_file, config_line, error, \
- "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \
- } while(false)
-
#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \
int function(const char *unit, \
const char *filename, \
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 6dc04d51e4..5680f01bd9 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -379,9 +379,8 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {
return 0;
}
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) {
+void dns_name_hash_func(const void *s, struct siphash *state) {
const char *p = s;
- unsigned long ul = hash_key[0];
int r;
assert(p);
@@ -400,13 +399,17 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
if (k > 0)
r = k;
+ if (r == 0)
+ break;
+
label[r] = 0;
ascii_strlower(label);
- ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key);
+ string_hash_func(label, state);
}
- return ul;
+ /* enforce that all names are terminated by the empty label */
+ string_hash_func("", state);
}
int dns_name_compare_func(const void *a, const void *b) {
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 8e73d9c20f..1f0d242c18 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -54,7 +54,7 @@ static inline int dns_name_is_valid(const char *s) {
return 1;
}
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]);
+void dns_name_hash_func(const void *s, struct siphash *state);
int dns_name_compare_func(const void *a, const void *b);
extern const struct hash_ops dns_name_hash_ops;
diff --git a/src/shared/dropin.c b/src/shared/dropin.c
index 963d05d32e..1845068adb 100644
--- a/src/shared/dropin.c
+++ b/src/shared/dropin.c
@@ -78,7 +78,7 @@ int write_drop_in(const char *dir, const char *unit, unsigned level,
if (r < 0)
return r;
- mkdir_p(p, 0755);
+ (void) mkdir_p(p, 0755);
return write_string_file_atomic_label(q, data);
}
@@ -132,8 +132,7 @@ static int iterate_dir(
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open directory %s: %m", path);
- return -errno;
+ return log_error_errno(errno, "Failed to open directory %s: %m", path);
}
for (;;) {
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
index e231a0ff80..c065adcfdf 100644
--- a/src/shared/fstab-util.c
+++ b/src/shared/fstab-util.c
@@ -20,9 +20,25 @@
***/
#include "fstab-util.h"
+#include "path-util.h"
#include "strv.h"
#include "util.h"
+bool fstab_is_mount_point(const char *mount) {
+ _cleanup_endmntent_ FILE *f = NULL;
+ struct mntent *m;
+
+ f = setmntent("/etc/fstab", "r");
+ if (!f)
+ return false;
+
+ while ((m = getmntent(f)))
+ if (path_equal(m->mnt_dir, mount))
+ return true;
+
+ return false;
+}
+
int fstab_filter_options(const char *opts, const char *names,
const char **namefound, char **value, char **filtered) {
const char *name, *n = NULL, *x;
diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
index 387c562a96..872b2363cd 100644
--- a/src/shared/fstab-util.h
+++ b/src/shared/fstab-util.h
@@ -25,6 +25,7 @@
#include <stddef.h>
#include "macro.h"
+bool fstab_is_mount_point(const char *mount);
int fstab_filter_options(const char *opts, const char *names,
const char **namefound, char **value, char **filtered);
diff --git a/src/shared/install.c b/src/shared/install.c
index 3d2b5ae77f..238433c808 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -949,8 +949,7 @@ static int config_parse_also(
return r;
}
if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 7790c1a3c8..dbc07aa7ad 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -117,11 +117,11 @@ static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, Output
if (flags & OUTPUT_COLOR) {
if (priority <= LOG_ERR) {
- color_on = ANSI_HIGHLIGHT_RED_ON;
- color_off = ANSI_HIGHLIGHT_OFF;
+ color_on = ANSI_HIGHLIGHT_RED;
+ color_off = ANSI_NORMAL;
} else if (priority <= LOG_NOTICE) {
- color_on = ANSI_HIGHLIGHT_ON;
- color_off = ANSI_HIGHLIGHT_OFF;
+ color_on = ANSI_HIGHLIGHT;
+ color_off = ANSI_NORMAL;
}
}
@@ -455,8 +455,8 @@ static int output_verbose(
fieldlen = c - (const char*) data;
if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
- on = ANSI_HIGHLIGHT_ON;
- off = ANSI_HIGHLIGHT_OFF;
+ on = ANSI_HIGHLIGHT;
+ off = ANSI_NORMAL;
}
if (flags & OUTPUT_SHOW_ALL ||
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index 70220bdd14..9c1e4d5e13 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -19,16 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/statfs.h>
-#include <linux/fs.h>
#include <fcntl.h>
+#include <linux/fs.h>
+#include <sys/statfs.h>
-#include "utf8.h"
#include "btrfs-util.h"
-#include "path-util.h"
#include "copy.h"
#include "mkdir.h"
+#include "path-util.h"
#include "rm-rf.h"
+#include "strv.h"
+#include "utf8.h"
+
#include "machine-image.h"
static const char image_search_path[] =
@@ -47,6 +49,38 @@ Image *image_unref(Image *i) {
return NULL;
}
+static char **image_settings_path(Image *image) {
+ _cleanup_strv_free_ char **l = NULL;
+ char **ret;
+ const char *fn, *s;
+ unsigned i = 0;
+
+ assert(image);
+
+ l = new0(char*, 4);
+ if (!l)
+ return NULL;
+
+ fn = strjoina(image->name, ".nspawn");
+
+ FOREACH_STRING(s, "/etc/systemd/nspawn/", "/run/systemd/nspawn/") {
+ l[i] = strappend(s, fn);
+ if (!l[i])
+ return NULL;
+
+ i++;
+ }
+
+ l[i] = file_in_same_dir(image->path, fn);
+ if (!l[i])
+ return NULL;
+
+ ret = l;
+ l = NULL;
+
+ return ret;
+}
+
static int image_new(
ImageType t,
const char *pretty,
@@ -341,6 +375,8 @@ void image_hashmap_free(Hashmap *map) {
int image_remove(Image *i) {
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
+ _cleanup_strv_free_ char **settings = NULL;
+ char **j;
int r;
assert(i);
@@ -349,6 +385,10 @@ int image_remove(Image *i) {
path_startswith(i->path, "/usr"))
return -EROFS;
+ settings = image_settings_path(i);
+ if (!settings)
+ return -ENOMEM;
+
/* Make sure we don't interfere with a running nspawn */
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
if (r < 0)
@@ -357,28 +397,56 @@ int image_remove(Image *i) {
switch (i->type) {
case IMAGE_SUBVOLUME:
- return btrfs_subvol_remove(i->path, true);
+ r = btrfs_subvol_remove(i->path, true);
+ if (r < 0)
+ return r;
+ break;
case IMAGE_DIRECTORY:
/* Allow deletion of read-only directories */
(void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
- return rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+ r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+ if (r < 0)
+ return r;
+
+ break;
case IMAGE_RAW:
if (unlink(i->path) < 0)
return -errno;
-
- return 0;
+ break;
default:
return -EOPNOTSUPP;
}
+
+ STRV_FOREACH(j, settings) {
+ if (unlink(*j) < 0 && errno != ENOENT)
+ log_debug_errno(errno, "Failed to unlink %s, ignoring: %m", *j);
+ }
+
+ return 0;
+}
+
+static int rename_settings_file(const char *path, const char *new_name) {
+ _cleanup_free_ char *rs = NULL;
+ const char *fn;
+
+ fn = strjoina(new_name, ".nspawn");
+
+ rs = file_in_same_dir(path, fn);
+ if (!rs)
+ return -ENOMEM;
+
+ return rename_noreplace(AT_FDCWD, path, AT_FDCWD, rs);
}
int image_rename(Image *i, const char *new_name) {
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT, name_lock = LOCK_FILE_INIT;
_cleanup_free_ char *new_path = NULL, *nn = NULL;
+ _cleanup_strv_free_ char **settings = NULL;
unsigned file_attr = 0;
+ char **j;
int r;
assert(i);
@@ -390,6 +458,10 @@ int image_rename(Image *i, const char *new_name) {
path_startswith(i->path, "/usr"))
return -EROFS;
+ settings = image_settings_path(i);
+ if (!settings)
+ return -ENOMEM;
+
/* Make sure we don't interfere with a running nspawn */
r = image_path_lock(i->path, LOCK_EX|LOCK_NB, &global_lock, &local_lock);
if (r < 0)
@@ -458,12 +530,33 @@ int image_rename(Image *i, const char *new_name) {
i->name = nn;
nn = NULL;
+ STRV_FOREACH(j, settings) {
+ r = rename_settings_file(*j, new_name);
+ if (r < 0 && r != -ENOENT)
+ log_debug_errno(r, "Failed to rename settings file %s, ignoring: %m", *j);
+ }
+
return 0;
}
+static int clone_settings_file(const char *path, const char *new_name) {
+ _cleanup_free_ char *rs = NULL;
+ const char *fn;
+
+ fn = strjoina(new_name, ".nspawn");
+
+ rs = file_in_same_dir(path, fn);
+ if (!rs)
+ return -ENOMEM;
+
+ return copy_file_atomic(path, rs, 0664, false, 0);
+}
+
int image_clone(Image *i, const char *new_name, bool read_only) {
_cleanup_release_lock_file_ LockFile name_lock = LOCK_FILE_INIT;
+ _cleanup_strv_free_ char **settings = NULL;
const char *new_path;
+ char **j;
int r;
assert(i);
@@ -471,6 +564,10 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
if (!image_name_is_valid(new_name))
return -EINVAL;
+ settings = image_settings_path(i);
+ if (!settings)
+ return -ENOMEM;
+
/* Make sure nobody takes the new name, between the time we
* checked it is currently unused in all search paths, and the
* time we take possesion of it */
@@ -506,6 +603,12 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
if (r < 0)
return r;
+ STRV_FOREACH(j, settings) {
+ r = clone_settings_file(*j, new_name);
+ if (r < 0 && r != -ENOENT)
+ log_debug_errno(r, "Failed to clone settings %s, ignoring: %m", *j);
+ }
+
return 0;
}
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 41da820938..d8f0fb404d 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -48,24 +48,27 @@ noreturn static void pager_fallback(void) {
}
int pager_open(bool jump_to_end) {
- int fd[2];
+ _cleanup_close_pair_ int fd[2] = { -1, -1 };
const char *pager;
pid_t parent_pid;
- int r;
if (pager_pid > 0)
return 1;
- if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER")))
- if (!*pager || streq(pager, "cat"))
- return 0;
-
if (!on_tty())
return 0;
+ pager = getenv("SYSTEMD_PAGER");
+ if (!pager)
+ pager = getenv("PAGER");
+
+ /* If the pager is explicitly turned off, honour it */
+ if (pager && (pager[0] == 0 || streq(pager, "cat")))
+ return 0;
+
/* Determine and cache number of columns before we spawn the
* pager so that we get the value from the actual tty */
- columns();
+ (void) columns();
if (pipe(fd) < 0)
return log_error_errno(errno, "Failed to create pager pipe: %m");
@@ -73,11 +76,8 @@ int pager_open(bool jump_to_end) {
parent_pid = getpid();
pager_pid = fork();
- if (pager_pid < 0) {
- r = log_error_errno(errno, "Failed to fork pager: %m");
- safe_close_pair(fd);
- return r;
- }
+ if (pager_pid < 0)
+ return log_error_errno(errno, "Failed to fork pager: %m");
/* In the child start the pager */
if (pager_pid == 0) {
@@ -86,7 +86,7 @@ int pager_open(bool jump_to_end) {
(void) reset_all_signal_handlers();
(void) reset_signal_mask();
- dup2(fd[0], STDIN_FILENO);
+ (void) dup2(fd[0], STDIN_FILENO);
safe_close_pair(fd);
/* Initialize a good set of less options */
@@ -141,7 +141,6 @@ int pager_open(bool jump_to_end) {
if (dup2(fd[1], STDERR_FILENO) < 0)
return log_error_errno(errno, "Failed to duplicate pager pipe: %m");
- safe_close_pair(fd);
return 1;
}
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index d803bbe07e..34eec959ef 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -181,7 +181,7 @@ static char** user_dirs(
if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
return NULL;
- if (strv_extend_strv(&res, (char**) config_unit_paths) < 0)
+ if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
return NULL;
if (runtime_dir)
@@ -203,7 +203,7 @@ static char** user_dirs(
if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
return NULL;
- if (strv_extend_strv(&res, (char**) data_unit_paths) < 0)
+ if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
return NULL;
if (generator_late)
@@ -318,7 +318,7 @@ int lookup_paths_init(
if (!unit_path)
return -ENOMEM;
- r = strv_extend_strv(&p->unit_path, unit_path);
+ r = strv_extend_strv(&p->unit_path, unit_path, false);
if (r < 0)
return r;
}
diff --git a/src/shared/pty.c b/src/shared/pty.c
deleted file mode 100644
index 35d9ff5f4d..0000000000
--- a/src/shared/pty.c
+++ /dev/null
@@ -1,633 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * PTY
- * A PTY object represents a single PTY connection between a master and a
- * child. The child process is fork()ed so the caller controls what program
- * will be run.
- *
- * Programs like /bin/login tend to perform a vhangup() on their TTY
- * before running the login procedure. This also causes the pty master
- * to get a EPOLLHUP event as long as no client has the TTY opened.
- * This means, we cannot use the TTY connection as reliable way to track
- * the client. Instead, we _must_ rely on the PID of the client to track
- * them.
- * However, this has the side effect that if the client forks and the
- * parent exits, we loose them and restart the client. But this seems to
- * be the expected behavior so we implement it here.
- *
- * Unfortunately, epoll always polls for EPOLLHUP so as long as the
- * vhangup() is ongoing, we will _always_ get EPOLLHUP and cannot sleep.
- * This gets worse if the client closes the TTY but doesn't exit.
- * Therefore, the fd must be edge-triggered in the epoll-set so we
- * only get the events once they change.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-#include <termios.h>
-#include <unistd.h>
-
-#include "barrier.h"
-#include "macro.h"
-#include "ring.h"
-#include "util.h"
-#include "signal-util.h"
-#include "pty.h"
-
-#define PTY_BUFSIZE 4096
-
-enum {
- PTY_ROLE_UNKNOWN,
- PTY_ROLE_PARENT,
- PTY_ROLE_CHILD,
-};
-
-struct Pty {
- unsigned long ref;
- Barrier barrier;
- int fd;
- pid_t child;
- sd_event_source *fd_source;
- sd_event_source *child_source;
-
- char in_buf[PTY_BUFSIZE];
- Ring out_buf;
-
- pty_event_t event_fn;
- void *event_fn_userdata;
-
- bool needs_requeue : 1;
- unsigned int role : 2;
-};
-
-int pty_new(Pty **out) {
- _pty_unref_ Pty *pty = NULL;
- int r;
-
- assert_return(out, -EINVAL);
-
- pty = new0(Pty, 1);
- if (!pty)
- return -ENOMEM;
-
- pty->ref = 1;
- pty->fd = -1;
- pty->barrier = (Barrier) BARRIER_NULL;
-
- pty->fd = posix_openpt(O_RDWR | O_NOCTTY | O_CLOEXEC | O_NONBLOCK);
- if (pty->fd < 0)
- return -errno;
-
- /*
- * The slave-node is initialized to uid/gid of the caller of
- * posix_openpt(). Only if devpts is mounted with fixed uid/gid this is
- * skipped. In that case, grantpt() can overwrite these, but then you
- * have to be root to use chown() (or a pt_chown helper has to be
- * present). In those cases grantpt() really does something,
- * otherwise it's a no-op. We call grantpt() here to try supporting
- * those cases, even though no-one uses that, I guess. If you need other
- * access-rights, set them yourself after this call returns (no, this is
- * not racy, it looks racy, but races regarding your own UID are never
- * important as an attacker could ptrace you; and the slave-pty is also
- * still locked).
- */
- r = grantpt(pty->fd);
- if (r < 0)
- return -errno;
-
- r = barrier_create(&pty->barrier);
- if (r < 0)
- return r;
-
- *out = pty;
- pty = NULL;
- return 0;
-}
-
-Pty *pty_ref(Pty *pty) {
- if (!pty || pty->ref < 1)
- return NULL;
-
- ++pty->ref;
- return pty;
-}
-
-Pty *pty_unref(Pty *pty) {
- if (!pty || pty->ref < 1 || --pty->ref > 0)
- return NULL;
-
- pty_close(pty);
- pty->child_source = sd_event_source_unref(pty->child_source);
- barrier_destroy(&pty->barrier);
- ring_clear(&pty->out_buf);
- free(pty);
-
- return NULL;
-}
-
-Barrier *pty_get_barrier(Pty *pty) {
- assert(pty);
- return &pty->barrier;
-}
-
-bool pty_is_unknown(Pty *pty) {
- return pty && pty->role == PTY_ROLE_UNKNOWN;
-}
-
-bool pty_is_parent(Pty *pty) {
- return pty && pty->role == PTY_ROLE_PARENT;
-}
-
-bool pty_is_child(Pty *pty) {
- return pty && pty->role == PTY_ROLE_CHILD;
-}
-
-bool pty_has_child(Pty *pty) {
- return pty_is_parent(pty) && pty->child > 0;
-}
-
-pid_t pty_get_child(Pty *pty) {
- return pty_has_child(pty) ? pty->child : -ECHILD;
-}
-
-bool pty_is_open(Pty *pty) {
- return pty && pty->fd >= 0;
-}
-
-int pty_get_fd(Pty *pty) {
- assert_return(pty, -EINVAL);
-
- return pty_is_open(pty) ? pty->fd : -EPIPE;
-}
-
-int pty_make_child(Pty *pty) {
- _cleanup_free_ char *slave_name = NULL;
- int r, fd;
-
- assert_return(pty, -EINVAL);
- assert_return(pty_is_unknown(pty), -EALREADY);
-
- r = ptsname_malloc(pty->fd, &slave_name);
- if (r < 0)
- return -errno;
-
- fd = open(slave_name, O_RDWR | O_CLOEXEC | O_NOCTTY);
- if (fd < 0)
- return -errno;
-
- safe_close(pty->fd);
- pty->fd = fd;
- pty->child = getpid();
- pty->role = PTY_ROLE_CHILD;
- barrier_set_role(&pty->barrier, BARRIER_CHILD);
-
- return 0;
-}
-
-int pty_make_parent(Pty *pty, pid_t child) {
- assert_return(pty, -EINVAL);
- assert_return(pty_is_unknown(pty), -EALREADY);
-
- pty->child = child;
- pty->role = PTY_ROLE_PARENT;
-
- return 0;
-}
-
-int pty_unlock(Pty *pty) {
- assert_return(pty, -EINVAL);
- assert_return(pty_is_unknown(pty) || pty_is_parent(pty), -EINVAL);
- assert_return(pty_is_open(pty), -ENODEV);
-
- return unlockpt(pty->fd) < 0 ? -errno : 0;
-}
-
-int pty_setup_child(Pty *pty) {
- struct termios attr;
- pid_t pid;
- int r;
-
- assert_return(pty, -EINVAL);
- assert_return(pty_is_child(pty), -EINVAL);
- assert_return(pty_is_open(pty), -EALREADY);
-
- r = reset_signal_mask();
- if (r < 0)
- return r;
-
- r = reset_all_signal_handlers();
- if (r < 0)
- return r;
-
- pid = setsid();
- if (pid < 0 && errno != EPERM)
- return -errno;
-
- r = ioctl(pty->fd, TIOCSCTTY, 0);
- if (r < 0)
- return -errno;
-
- r = tcgetattr(pty->fd, &attr);
- if (r < 0)
- return -errno;
-
- /* erase character should be normal backspace, PLEASEEE! */
- attr.c_cc[VERASE] = 010;
- /* always set UTF8 flag */
- attr.c_iflag |= IUTF8;
-
- r = tcsetattr(pty->fd, TCSANOW, &attr);
- if (r < 0)
- return -errno;
-
- if (dup2(pty->fd, STDIN_FILENO) != STDIN_FILENO ||
- dup2(pty->fd, STDOUT_FILENO) != STDOUT_FILENO ||
- dup2(pty->fd, STDERR_FILENO) != STDERR_FILENO)
- return -errno;
-
- /* only close FD if it's not a std-fd */
- pty->fd = (pty->fd > 2) ? safe_close(pty->fd) : -1;
-
- return 0;
-}
-
-void pty_close(Pty *pty) {
- if (!pty_is_open(pty))
- return;
-
- pty->fd_source = sd_event_source_unref(pty->fd_source);
- pty->fd = safe_close(pty->fd);
-}
-
-/*
- * Drain input-queue and dispatch data via the event-handler. Returns <0 on
- * error, 0 if queue is empty and 1 if we couldn't empty the input queue fast
- * enough and there's still data left.
- */
-static int pty_dispatch_read(Pty *pty) {
- unsigned int i;
- ssize_t len;
- int r;
-
- /*
- * We're edge-triggered, means we need to read the whole queue. This,
- * however, might cause us to stall if the writer is faster than we
- * are. Therefore, try reading as much as 8 times (32KiB) and only
- * bail out then.
- */
-
- for (i = 0; i < 8; ++i) {
- len = read(pty->fd, pty->in_buf, sizeof(pty->in_buf) - 1);
- if (len < 0) {
- if (errno == EINTR)
- continue;
-
- return (errno == EAGAIN) ? 0 : -errno;
- } else if (len == 0)
- continue;
-
- /* set terminating zero for debugging safety */
- pty->in_buf[len] = 0;
- r = pty->event_fn(pty, pty->event_fn_userdata, PTY_DATA, pty->in_buf, len);
- if (r < 0)
- return r;
- }
-
- /* still data left, make sure we're queued again */
- pty->needs_requeue = true;
-
- return 1;
-}
-
-/*
- * Drain output-queue by writing data to the pty. Returns <0 on error, 0 if the
- * output queue is empty now and 1 if we couldn't empty the output queue fast
- * enough and there's still data left.
- */
-static int pty_dispatch_write(Pty *pty) {
- struct iovec vec[2];
- unsigned int i;
- ssize_t len;
- size_t num;
-
- /*
- * Same as pty_dispatch_read(), we're edge-triggered so we need to call
- * write() until either all data is written or it returns EAGAIN. We
- * call it twice and if it still writes successfully, we reschedule.
- */
-
- for (i = 0; i < 2; ++i) {
- num = ring_peek(&pty->out_buf, vec);
- if (num < 1)
- return 0;
-
- len = writev(pty->fd, vec, (int)num);
- if (len < 0) {
- if (errno == EINTR)
- continue;
-
- return (errno == EAGAIN) ? 1 : -errno;
- } else if (len == 0)
- continue;
-
- ring_pull(&pty->out_buf, (size_t)len);
- }
-
- /* still data left, make sure we're queued again */
- if (ring_get_size(&pty->out_buf) > 0) {
- pty->needs_requeue = true;
- return 1;
- }
-
- return 0;
-}
-
-static int pty_fd_fn(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- Pty *pty = userdata;
- int r_hup = 0, r_write = 0, r_read = 0, r;
-
- /*
- * Whenever we encounter I/O errors, we have to make sure to drain the
- * input queue first, before we handle any HUP. A child might send us
- * a message and immediately close the queue. We must not handle the
- * HUP first or we loose data.
- * Therefore, if we read a message successfully, we always return
- * success and wait for the next event-loop iteration. Furthermore,
- * whenever there is a write-error, we must try reading from the input
- * queue even if EPOLLIN is not set. The input might have arrived in
- * between epoll_wait() and write(). Therefore, write-errors are only
- * ever handled if the input-queue is empty. In all other cases they
- * are ignored until either reading fails or the input queue is empty.
- */
-
- if (revents & (EPOLLHUP | EPOLLERR))
- r_hup = -EPIPE;
-
- if (revents & EPOLLOUT)
- r_write = pty_dispatch_write(pty);
-
- /* Awesome! Kernel signals HUP without IN but queues are not empty.. */
- if ((revents & EPOLLIN) || r_hup < 0 || r_write < 0) {
- r_read = pty_dispatch_read(pty);
- if (r_read > 0)
- return 0; /* still data left to fetch next round */
- }
-
- if (r_hup < 0 || r_write < 0 || r_read < 0) {
- /* PTY closed and input-queue drained */
- pty_close(pty);
- r = pty->event_fn(pty, pty->event_fn_userdata, PTY_HUP, NULL, 0);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int pty_fd_prepare_fn(sd_event_source *source, void *userdata) {
- Pty *pty = userdata;
- int r;
-
- if (pty->needs_requeue) {
- /*
- * We're edge-triggered. In case we couldn't handle all events
- * or in case new write-data is queued, we set needs_requeue.
- * Before going asleep, we set the io-events *again*. sd-event
- * notices that we're edge-triggered and forwards the call to
- * the kernel even if the events didn't change. The kernel will
- * check the events and re-queue us on the ready queue in case
- * an event is pending.
- */
- r = sd_event_source_set_io_events(source, EPOLLHUP | EPOLLERR | EPOLLIN | EPOLLOUT | EPOLLET);
- if (r >= 0)
- pty->needs_requeue = false;
- }
-
- return 0;
-}
-
-static int pty_child_fn(sd_event_source *source, const siginfo_t *si, void *userdata) {
- Pty *pty = userdata;
- int r;
-
- pty->child = 0;
-
- r = pty->event_fn(pty, pty->event_fn_userdata, PTY_CHILD, si, sizeof(*si));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int pty_attach_event(Pty *pty, sd_event *event, pty_event_t event_fn, void *event_fn_userdata) {
- int r;
-
- assert_return(pty, -EINVAL);
- assert_return(event, -EINVAL);
- assert_return(event_fn, -EINVAL);
- assert_return(pty_is_parent(pty), -EINVAL);
-
- pty_detach_event(pty);
-
- if (pty_is_open(pty)) {
- r = sd_event_add_io(event,
- &pty->fd_source,
- pty->fd,
- EPOLLHUP | EPOLLERR | EPOLLIN | EPOLLOUT | EPOLLET,
- pty_fd_fn,
- pty);
- if (r < 0)
- goto error;
-
- r = sd_event_source_set_prepare(pty->fd_source, pty_fd_prepare_fn);
- if (r < 0)
- goto error;
- }
-
- if (pty_has_child(pty)) {
- r = sd_event_add_child(event,
- &pty->child_source,
- pty->child,
- WEXITED,
- pty_child_fn,
- pty);
- if (r < 0)
- goto error;
- }
-
- pty->event_fn = event_fn;
- pty->event_fn_userdata = event_fn_userdata;
-
- return 0;
-
-error:
- pty_detach_event(pty);
- return r;
-}
-
-void pty_detach_event(Pty *pty) {
- if (!pty)
- return;
-
- pty->child_source = sd_event_source_unref(pty->child_source);
- pty->fd_source = sd_event_source_unref(pty->fd_source);
- pty->event_fn = NULL;
- pty->event_fn_userdata = NULL;
-}
-
-int pty_write(Pty *pty, const void *buf, size_t size) {
- bool was_empty;
- int r;
-
- assert_return(pty, -EINVAL);
- assert_return(pty_is_open(pty), -ENODEV);
- assert_return(pty_is_parent(pty), -ENODEV);
-
- if (size < 1)
- return 0;
-
- /*
- * Push @buf[0..@size] into the output ring-buffer. In case the
- * ring-buffer wasn't empty beforehand, we're already waiting for
- * EPOLLOUT and we're done. If it was empty, we have to re-queue the
- * FD for EPOLLOUT as we're edge-triggered and wouldn't get any new
- * EPOLLOUT event.
- */
-
- was_empty = ring_get_size(&pty->out_buf) < 1;
-
- r = ring_push(&pty->out_buf, buf, size);
- if (r < 0)
- return r;
-
- if (was_empty)
- pty->needs_requeue = true;
-
- return 0;
-}
-
-int pty_signal(Pty *pty, int sig) {
- assert_return(pty, -EINVAL);
- assert_return(pty_is_open(pty), -ENODEV);
- assert_return(pty_is_parent(pty), -ENODEV);
-
- return ioctl(pty->fd, TIOCSIG, sig) < 0 ? -errno : 0;
-}
-
-int pty_resize(Pty *pty, unsigned short term_width, unsigned short term_height) {
- struct winsize ws = {
- .ws_col = term_width,
- .ws_row = term_height,
- };
-
- assert_return(pty, -EINVAL);
- assert_return(pty_is_open(pty), -ENODEV);
- assert_return(pty_is_parent(pty), -ENODEV);
-
- /*
- * This will send SIGWINCH to the pty slave foreground process group.
- * We will also get one, but we don't need it.
- */
- return ioctl(pty->fd, TIOCSWINSZ, &ws) < 0 ? -errno : 0;
-}
-
-pid_t pty_fork(Pty **out, sd_event *event, pty_event_t event_fn, void *event_fn_userdata, unsigned short initial_term_width, unsigned short initial_term_height) {
- _pty_unref_ Pty *pty = NULL;
- int r;
- pid_t pid;
-
- assert_return(out, -EINVAL);
- assert_return((event && event_fn) || (!event && !event_fn), -EINVAL);
-
- r = pty_new(&pty);
- if (r < 0)
- return r;
-
- r = pty_unlock(pty);
- if (r < 0)
- return r;
-
- pid = fork();
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
- /* child */
-
- r = pty_make_child(pty);
- if (r < 0)
- _exit(-r);
-
- r = pty_setup_child(pty);
- if (r < 0)
- _exit(-r);
-
- /* sync with parent */
- if (!barrier_place_and_sync(&pty->barrier))
- _exit(1);
-
- /* fallthrough and return the child's PTY object */
- } else {
- /* parent */
-
- r = pty_make_parent(pty, pid);
- if (r < 0)
- goto parent_error;
-
- r = pty_resize(pty, initial_term_width, initial_term_height);
- if (r < 0)
- goto parent_error;
-
- if (event) {
- r = pty_attach_event(pty, event, event_fn, event_fn_userdata);
- if (r < 0)
- goto parent_error;
- }
-
- /* sync with child */
- if (!barrier_place_and_sync(&pty->barrier)) {
- r = -ECHILD;
- goto parent_error;
- }
-
- /* fallthrough and return the parent's PTY object */
- }
-
- *out = pty;
- pty = NULL;
- return pid;
-
-parent_error:
- barrier_abort(&pty->barrier);
- waitpid(pty->child, NULL, 0);
- pty->child = 0;
- return r;
-}
diff --git a/src/shared/pty.h b/src/shared/pty.h
deleted file mode 100644
index 63c7db2833..0000000000
--- a/src/shared/pty.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <unistd.h>
-
-#include "barrier.h"
-#include "macro.h"
-#include "sd-event.h"
-
-typedef struct Pty Pty;
-
-enum {
- PTY_CHILD,
- PTY_HUP,
- PTY_DATA,
-};
-
-typedef int (*pty_event_t) (Pty *pty, void *userdata, unsigned int event, const void *ptr, size_t size);
-
-int pty_new(Pty **out);
-Pty *pty_ref(Pty *pty);
-Pty *pty_unref(Pty *pty);
-
-#define _pty_unref_ _cleanup_(pty_unrefp)
-DEFINE_TRIVIAL_CLEANUP_FUNC(Pty*, pty_unref);
-
-Barrier *pty_get_barrier(Pty *pty);
-
-bool pty_is_unknown(Pty *pty);
-bool pty_is_parent(Pty *pty);
-bool pty_is_child(Pty *pty);
-bool pty_has_child(Pty *pty);
-pid_t pty_get_child(Pty *pty);
-
-bool pty_is_open(Pty *pty);
-int pty_get_fd(Pty *pty);
-
-int pty_make_child(Pty *pty);
-int pty_make_parent(Pty *pty, pid_t child);
-int pty_unlock(Pty *pty);
-int pty_setup_child(Pty *pty);
-void pty_close(Pty *pty);
-
-int pty_attach_event(Pty *pty, sd_event *event, pty_event_t event_fn, void *event_fn_userdata);
-void pty_detach_event(Pty *pty);
-
-int pty_write(Pty *pty, const void *buf, size_t size);
-int pty_signal(Pty *pty, int sig);
-int pty_resize(Pty *pty, unsigned short term_width, unsigned short term_height);
-
-pid_t pty_fork(Pty **out, sd_event *event, pty_event_t event_fn, void *event_fn_userdata, unsigned short initial_term_width, unsigned short initial_term_height);
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index 789f217efc..7749f20540 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -32,6 +32,8 @@ struct PTYForward {
int master;
+ PTYForwardFlags flags;
+
sd_event_source *stdin_event_source;
sd_event_source *stdout_event_source;
sd_event_source *master_event_source;
@@ -41,8 +43,6 @@ struct PTYForward {
struct termios saved_stdin_attr;
struct termios saved_stdout_attr;
- bool read_only:1;
-
bool saved_stdin:1;
bool saved_stdout:1;
@@ -54,8 +54,7 @@ struct PTYForward {
bool master_writable:1;
bool master_hangup:1;
- /* Continue reading after hangup? */
- bool ignore_vhangup:1;
+ bool read_from_master:1;
bool last_char_set:1;
char last_char;
@@ -100,6 +99,18 @@ static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) {
return false;
}
+static bool ignore_vhangup(PTYForward *f) {
+ assert(f);
+
+ if (f->flags & PTY_FORWARD_IGNORE_VHANGUP)
+ return true;
+
+ if ((f->flags & PTY_FORWARD_IGNORE_INITIAL_VHANGUP) && !f->read_from_master)
+ return true;
+
+ return false;
+}
+
static int shovel(PTYForward *f) {
ssize_t k;
@@ -179,7 +190,7 @@ static int shovel(PTYForward *f) {
* EAGAIN here and try again, unless
* ignore_vhangup is off. */
- if (errno == EAGAIN || (errno == EIO && f->ignore_vhangup))
+ if (errno == EAGAIN || (errno == EIO && ignore_vhangup(f)))
f->master_readable = false;
else if (errno == EPIPE || errno == ECONNRESET || errno == EIO) {
f->master_readable = f->master_writable = false;
@@ -190,8 +201,10 @@ static int shovel(PTYForward *f) {
log_error_errno(errno, "read(): %m");
return sd_event_exit(f->event, EXIT_FAILURE);
}
- } else
+ } else {
+ f->read_from_master = true;
f->out_buffer_full += (size_t) k;
+ }
}
if (f->stdout_writable && f->out_buffer_full > 0) {
@@ -302,8 +315,7 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo *
int pty_forward_new(
sd_event *event,
int master,
- bool ignore_vhangup,
- bool read_only,
+ PTYForwardFlags flags,
PTYForward **ret) {
_cleanup_(pty_forward_freep) PTYForward *f = NULL;
@@ -314,8 +326,7 @@ int pty_forward_new(
if (!f)
return -ENOMEM;
- f->read_only = read_only;
- f->ignore_vhangup = ignore_vhangup;
+ f->flags = flags;
if (event)
f->event = sd_event_ref(event);
@@ -325,7 +336,7 @@ int pty_forward_new(
return r;
}
- if (!read_only) {
+ if (!(flags & PTY_FORWARD_READ_ONLY)) {
r = fd_nonblock(STDIN_FILENO, true);
if (r < 0)
return r;
@@ -344,7 +355,7 @@ int pty_forward_new(
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
(void) ioctl(master, TIOCSWINSZ, &ws);
- if (!read_only) {
+ if (!(flags & PTY_FORWARD_READ_ONLY)) {
if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) {
struct termios raw_stdin_attr;
@@ -429,16 +440,20 @@ int pty_forward_get_last_char(PTYForward *f, char *ch) {
return 0;
}
-int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup) {
+int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) {
int r;
assert(f);
- if (f->ignore_vhangup == ignore_vhangup)
+ if (!!(f->flags & PTY_FORWARD_IGNORE_VHANGUP) == b)
return 0;
- f->ignore_vhangup = ignore_vhangup;
- if (!f->ignore_vhangup) {
+ if (b)
+ f->flags |= PTY_FORWARD_IGNORE_VHANGUP;
+ else
+ f->flags &= ~PTY_FORWARD_IGNORE_VHANGUP;
+
+ if (!ignore_vhangup(f)) {
/* We shall now react to vhangup()s? Let's check
* immediately if we might be in one */
@@ -455,5 +470,5 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup) {
int pty_forward_get_ignore_vhangup(PTYForward *f) {
assert(f);
- return f->ignore_vhangup;
+ return !!(f->flags & PTY_FORWARD_IGNORE_VHANGUP);
}
diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h
index 6f84e4036a..9b3214221b 100644
--- a/src/shared/ptyfwd.h
+++ b/src/shared/ptyfwd.h
@@ -27,7 +27,17 @@
typedef struct PTYForward PTYForward;
-int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, bool read_only, PTYForward **f);
+typedef enum PTYForwardFlags {
+ PTY_FORWARD_READ_ONLY = 1,
+
+ /* Continue reading after hangup? */
+ PTY_FORWARD_IGNORE_VHANGUP = 2,
+
+ /* Continue reading after hangup but only if we never read anything else? */
+ PTY_FORWARD_IGNORE_INITIAL_VHANGUP = 4,
+} PTYForwardFlags;
+
+int pty_forward_new(sd_event *event, int master, PTYForwardFlags flags, PTYForward **f);
PTYForward *pty_forward_free(PTYForward *f);
int pty_forward_get_last_char(PTYForward *f, char *ch);
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 1064fd5cbd..3dedbd1f62 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -226,7 +226,7 @@ static bool enough_memory_for_hibernation(void) {
if (r < 0)
return false;
- r = get_status_field("/proc/meminfo", "\nActive(anon):", &active);
+ r = get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE, &active);
if (r < 0) {
log_error_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m");
return false;
diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c
index 70466d17e5..29db855c67 100644
--- a/src/shared/spawn-ask-password-agent.c
+++ b/src/shared/spawn-ask-password-agent.c
@@ -19,13 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
-#include <signal.h>
#include "log.h"
-#include "util.h"
#include "process-util.h"
+#include "util.h"
#include "spawn-ask-password-agent.h"
static pid_t agent_pid = 0;
@@ -46,9 +46,9 @@ int ask_password_agent_open(void) {
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
if (r < 0)
- log_error_errno(r, "Failed to fork TTY ask password agent: %m");
+ return log_error_errno(r, "Failed to fork TTY ask password agent: %m");
- return r;
+ return 1;
}
void ask_password_agent_close(void) {
@@ -57,8 +57,8 @@ void ask_password_agent_close(void) {
return;
/* Inform agent that we are done */
- kill(agent_pid, SIGTERM);
- kill(agent_pid, SIGCONT);
+ (void) kill(agent_pid, SIGTERM);
+ (void) kill(agent_pid, SIGCONT);
(void) wait_for_terminate(agent_pid, NULL);
agent_pid = 0;
}
diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c
index 1de0b94fd5..b2cab948ef 100644
--- a/src/shared/sysctl-util.c
+++ b/src/shared/sysctl-util.c
@@ -19,18 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "fileio.h"
#include "log.h"
#include "util.h"
-#include "fileio.h"
-#include "build.h"
#include "sysctl-util.h"
char *sysctl_normalize(char *s) {
diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c
index 2b2310152d..1ba66eb998 100644
--- a/src/sleep/sleep.c
+++ b/src/sleep/sleep.c
@@ -20,18 +20,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
#include <getopt.h>
+#include <stdio.h>
#include "sd-messages.h"
-#include "log.h"
-#include "util.h"
-#include "strv.h"
+
+#include "def.h"
#include "fileio.h"
-#include "build.h"
+#include "log.h"
#include "sleep-config.h"
-#include "def.h"
+#include "strv.h"
+#include "util.h"
static char* arg_verb = NULL;
@@ -165,9 +165,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0; /* done */
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0 /* done */;
+ return version();
case '?':
return -EINVAL;
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index 715f440cb1..73c04fdfc0 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -20,12 +20,12 @@
***/
#include <errno.h>
+#include <fcntl.h>
#include <getopt.h>
+#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <netdb.h>
-#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
@@ -33,12 +33,12 @@
#include "sd-daemon.h"
#include "sd-event.h"
#include "sd-resolve.h"
+
#include "log.h"
+#include "path-util.h"
+#include "set.h"
#include "socket-util.h"
#include "util.h"
-#include "build.h"
-#include "set.h"
-#include "path-util.h"
#define BUFFER_SIZE (256 * 1024)
#define CONNECTIONS_MAX 256
@@ -603,9 +603,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case '?':
return -EINVAL;
diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c
index 618844382f..ee34209a30 100644
--- a/src/sysctl/sysctl.c
+++ b/src/sysctl/sysctl.c
@@ -19,23 +19,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <limits.h>
#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
-#include "log.h"
-#include "strv.h"
-#include "util.h"
-#include "hashmap.h"
-#include "path-util.h"
#include "conf-files.h"
#include "fileio.h"
-#include "build.h"
+#include "hashmap.h"
+#include "log.h"
+#include "path-util.h"
+#include "strv.h"
#include "sysctl-util.h"
+#include "util.h"
static char **arg_prefixes = NULL;
@@ -195,9 +194,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_PREFIX: {
char *p;
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index ce94dc9edf..420a246be1 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -20,59 +20,60 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
#include <getopt.h>
+#include <linux/reboot.h>
#include <locale.h>
#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
+#include <sys/reboot.h>
#include <sys/socket.h>
-#include <stddef.h>
+#include <unistd.h>
+#include "sd-bus.h"
#include "sd-daemon.h"
#include "sd-login.h"
-#include "sd-bus.h"
-#include "log.h"
-#include "util.h"
-#include "macro.h"
-#include "set.h"
-#include "utmp-wtmp.h"
-#include "special.h"
-#include "initreq.h"
-#include "path-util.h"
-#include "strv.h"
+
+#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-message.h"
+#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
-#include "list.h"
-#include "path-lookup.h"
-#include "exit-status.h"
-#include "build.h"
-#include "unit-name.h"
-#include "pager.h"
-#include "spawn-ask-password-agent.h"
-#include "spawn-polkit-agent.h"
-#include "install.h"
-#include "logs-show.h"
-#include "socket-util.h"
-#include "fileio.h"
#include "copy.h"
-#include "env-util.h"
-#include "bus-util.h"
-#include "bus-message.h"
-#include "bus-error.h"
-#include "bus-common-errors.h"
-#include "mkdir.h"
#include "dropin.h"
#include "efivars.h"
+#include "env-util.h"
+#include "exit-status.h"
+#include "fileio.h"
#include "formats-util.h"
-#include "process-util.h"
-#include "terminal-util.h"
#include "hostname-util.h"
+#include "initreq.h"
+#include "install.h"
+#include "list.h"
+#include "log.h"
+#include "logs-show.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "pager.h"
+#include "path-lookup.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "set.h"
#include "signal-util.h"
+#include "socket-util.h"
+#include "spawn-ask-password-agent.h"
+#include "spawn-polkit-agent.h"
+#include "special.h"
+#include "strv.h"
+#include "terminal-util.h"
+#include "unit-name.h"
+#include "util.h"
+#include "utmp-wtmp.h"
+#include "verbs.h"
static char **arg_types = NULL;
static char **arg_states = NULL;
@@ -100,7 +101,7 @@ static bool arg_quiet = false;
static bool arg_full = false;
static bool arg_recursive = false;
static int arg_force = 0;
-static bool arg_ask_password = true;
+static bool arg_ask_password = false;
static bool arg_runtime = false;
static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL;
static char **arg_wall = NULL;
@@ -133,23 +134,61 @@ static enum action {
_ACTION_MAX
} arg_action = ACTION_SYSTEMCTL;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
-static char *arg_host = NULL;
+static const char *arg_host = NULL;
static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
static bool arg_plain = false;
static bool arg_firmware_setup = false;
static bool arg_now = false;
-static bool original_stdout_is_tty;
-
-static int daemon_reload(sd_bus *bus, char **args);
+static int daemon_reload(int argc, char *argv[], void* userdata);
static int halt_now(enum action a);
static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet);
-static char** strv_skip_first(char **strv) {
- if (strv_length(strv) > 0)
- return strv + 1;
- return NULL;
+static bool original_stdout_is_tty;
+
+typedef enum BusFocus {
+ BUS_FULL, /* The full bus indicated via --system or --user */
+ BUS_MANAGER, /* The manager itself, possibly directly, possibly via the bus */
+ _BUS_FOCUS_MAX
+} BusFocus;
+
+static sd_bus *busses[_BUS_FOCUS_MAX] = {};
+
+static int acquire_bus(BusFocus focus, sd_bus **ret) {
+ int r;
+
+ assert(focus < _BUS_FOCUS_MAX);
+ assert(ret);
+
+ /* We only go directly to the manager, if we are using a local transport */
+ if (arg_transport != BUS_TRANSPORT_LOCAL)
+ focus = BUS_FULL;
+
+ if (!busses[focus]) {
+ bool user;
+
+ user = arg_scope != UNIT_FILE_SYSTEM;
+
+ if (focus == BUS_MANAGER)
+ r = bus_connect_transport_systemd(arg_transport, arg_host, user, &busses[focus]);
+ else
+ r = bus_connect_transport(arg_transport, arg_host, user, &busses[focus]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to bus: %m");
+
+ (void) sd_bus_set_allow_interactive_authorization(busses[focus], arg_ask_password);
+ }
+
+ *ret = busses[focus];
+ return 0;
+}
+
+static void release_busses(void) {
+ BusFocus w;
+
+ for (w = 0; w < _BUS_FOCUS_MAX; w++)
+ busses[w] = sd_bus_flush_close_unref(busses[w]);
}
static void pager_open_if_enabled(void) {
@@ -229,42 +268,10 @@ static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error)
return EXIT_FAILURE;
}
-static void warn_wall(enum action a) {
- static const char *table[_ACTION_MAX] = {
- [ACTION_HALT] = "The system is going down for system halt NOW!",
- [ACTION_REBOOT] = "The system is going down for reboot NOW!",
- [ACTION_POWEROFF] = "The system is going down for power-off NOW!",
- [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!",
- [ACTION_RESCUE] = "The system is going down to rescue mode NOW!",
- [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!",
- [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!"
- };
-
- if (arg_no_wall)
- return;
-
- if (arg_wall) {
- _cleanup_free_ char *p;
+static bool install_client_side(void) {
- p = strv_join(arg_wall, " ");
- if (!p) {
- log_oom();
- return;
- }
-
- if (*p) {
- utmp_wall(p, NULL, NULL, NULL, NULL);
- return;
- }
- }
-
- if (!table[a])
- return;
-
- utmp_wall(table[a], NULL, NULL, NULL, NULL);
-}
-
-static bool avoid_bus(void) {
+ /* Decides when to execute enable/disable/... operations
+ * client-side rather than server-side. */
if (running_in_chroot() > 0)
return true;
@@ -430,11 +437,11 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
if (STR_IN_SET(u->load_state, "error", "not-found", "masked") && !arg_plain) {
on_loaded = ansi_highlight_red();
on_circle = ansi_highlight_yellow();
- off_loaded = off_circle = ansi_highlight_off();
+ off_loaded = off_circle = ansi_normal();
circle = true;
} else if (streq(u->active_state, "failed") && !arg_plain) {
on_circle = on_active = ansi_highlight_red();
- off_circle = off_active = ansi_highlight_off();
+ off_circle = off_active = ansi_normal();
circle = true;
}
@@ -481,10 +488,10 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
"SUB = The low-level unit activation state, values depend on unit type.");
puts(job_count ? "JOB = Pending job for the unit.\n" : "");
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
}
if (arg_all)
@@ -651,15 +658,20 @@ static int get_unit_list_recursive(
return c;
}
-static int list_units(sd_bus *bus, char **args) {
+static int list_units(int argc, char *argv[], void *userdata) {
_cleanup_free_ UnitInfo *unit_infos = NULL;
_cleanup_(message_set_freep) Set *replies = NULL;
_cleanup_strv_free_ char **machines = NULL;
+ sd_bus *bus;
int r;
pager_open_if_enabled();
- r = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (r < 0)
return r;
@@ -675,6 +687,10 @@ static int get_triggered_units(
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
+ assert(bus);
+ assert(path);
+ assert(ret);
+
r = sd_bus_get_property_strv(
bus,
"org.freedesktop.systemd1",
@@ -683,9 +699,8 @@ static int get_triggered_units(
"Triggers",
&error,
ret);
-
if (r < 0)
- log_error("Failed to determine triggers: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to determine triggers: %s", bus_error_message(&error, r));
return 0;
}
@@ -709,10 +724,8 @@ static int get_listening(
&error,
&reply,
"a(ss)");
- if (r < 0) {
- log_error("Failed to get list of listening sockets: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get list of listening sockets: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
if (r < 0)
@@ -835,12 +848,12 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
}
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
}
if (!arg_no_legend) {
@@ -852,7 +865,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) {
return 0;
}
-static int list_sockets(sd_bus *bus, char **args) {
+static int list_sockets(int argc, char *argv[], void *userdata) {
_cleanup_(message_set_freep) Set *replies = NULL;
_cleanup_strv_free_ char **machines = NULL;
_cleanup_free_ UnitInfo *unit_infos = NULL;
@@ -862,10 +875,15 @@ static int list_sockets(sd_bus *bus, char **args) {
unsigned cs = 0;
size_t size = 0;
int r = 0, n;
+ sd_bus *bus;
pager_open_if_enabled();
- n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
return n;
@@ -946,10 +964,8 @@ static int get_next_elapse(
&error,
't',
&t.monotonic);
- if (r < 0) {
- log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r));
r = sd_bus_get_property_trivial(
bus,
@@ -960,10 +976,8 @@ static int get_next_elapse(
&error,
't',
&t.realtime);
- if (r < 0) {
- log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r));
*next = t;
return 0;
@@ -990,10 +1004,8 @@ static int get_last_trigger(
&error,
't',
last);
- if (r < 0) {
- log_error("Failed to get last trigger time: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get last trigger time: %s", bus_error_message(&error, r));
return 0;
}
@@ -1117,12 +1129,12 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) {
}
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
if (!arg_no_legend)
printf("\n");
} else {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
}
if (!arg_no_legend) {
@@ -1159,7 +1171,7 @@ static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) {
return next_elapse;
}
-static int list_timers(sd_bus *bus, char **args) {
+static int list_timers(int argc, char *argv[], void *userdata) {
_cleanup_(message_set_freep) Set *replies = NULL;
_cleanup_strv_free_ char **machines = NULL;
_cleanup_free_ struct timer_info *timer_infos = NULL;
@@ -1169,11 +1181,16 @@ static int list_timers(sd_bus *bus, char **args) {
size_t size = 0;
int n, c = 0;
dual_timestamp nw;
+ sd_bus *bus;
int r = 0;
pager_open_if_enabled();
- n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
return n;
@@ -1299,15 +1316,16 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
const char *on, *off;
const char *id;
- if (u->state == UNIT_FILE_MASKED ||
- u->state == UNIT_FILE_MASKED_RUNTIME ||
- u->state == UNIT_FILE_DISABLED ||
- u->state == UNIT_FILE_INVALID) {
+ if (IN_SET(u->state,
+ UNIT_FILE_MASKED,
+ UNIT_FILE_MASKED_RUNTIME,
+ UNIT_FILE_DISABLED,
+ UNIT_FILE_INVALID)) {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else if (u->state == UNIT_FILE_ENABLED) {
on = ansi_highlight_green();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -1324,7 +1342,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
printf("\n%u unit files listed.\n", c);
}
-static int list_unit_files(sd_bus *bus, char **args) {
+static int list_unit_files(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ UnitFileList *units = NULL;
UnitFileList *unit;
@@ -1336,7 +1354,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
pager_open_if_enabled();
- if (avoid_bus()) {
+ if (install_client_side()) {
Hashmap *h;
UnitFileList *u;
Iterator i;
@@ -1349,8 +1367,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
r = unit_file_get_list(arg_scope, arg_root, h);
if (r < 0) {
unit_file_list_free(h);
- log_error_errno(r, "Failed to get unit file list: %m");
- return r;
+ return log_error_errno(r, "Failed to get unit file list: %m");
}
n_units = hashmap_size(h);
@@ -1362,7 +1379,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
}
HASHMAP_FOREACH(u, h, i) {
- if (!output_show_unit_file(u, strv_skip_first(args)))
+ if (!output_show_unit_file(u, strv_skip(argv, 1)))
continue;
units[c++] = *u;
@@ -1373,6 +1390,11 @@ static int list_unit_files(sd_bus *bus, char **args) {
hashmap_free(h);
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
r = sd_bus_call_method(
bus,
@@ -1383,10 +1405,8 @@ static int list_unit_files(sd_bus *bus, char **args) {
&error,
&reply,
NULL);
- if (r < 0) {
- log_error("Failed to list unit files: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)");
if (r < 0)
@@ -1402,7 +1422,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
unit_file_state_from_string(state)
};
- if (output_show_unit_file(&units[c], strv_skip_first(args)))
+ if (output_show_unit_file(&units[c], strv_skip(argv, 1)))
c ++;
}
@@ -1417,7 +1437,7 @@ static int list_unit_files(sd_bus *bus, char **args) {
qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
output_unit_file_list(units, c);
- if (avoid_bus()) {
+ if (install_client_side()) {
for (unit = units; unit < units + c; unit++)
free(unit->path);
}
@@ -1476,6 +1496,8 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
"BindsTo\0",
[DEPENDENCY_REVERSE] = "RequiredBy\0"
"RequiredByOverridable\0"
+ "RequisiteOf\0"
+ "RequisiteOfOverridable\0"
"WantedBy\0"
"PartOf\0"
"BoundBy\0",
@@ -1507,10 +1529,8 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
&error,
&reply,
"s", "org.freedesktop.systemd1.Unit");
- if (r < 0) {
- log_error("Failed to get properties of %s: %s", name, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
if (r < 0)
@@ -1614,7 +1634,7 @@ static int list_dependencies_one(
state = check_one_unit(bus, *c, "activating\0active\0reloading\0", true);
on = state > 0 ? ansi_highlight_green() : ansi_highlight_red();
- printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_highlight_off());
+ printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal());
}
r = list_dependencies_print(*c, level, branches, c[1] == NULL);
@@ -1634,16 +1654,15 @@ static int list_dependencies_one(
return 0;
}
-static int list_dependencies(sd_bus *bus, char **args) {
+static int list_dependencies(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **units = NULL;
_cleanup_free_ char *unit = NULL;
const char *u;
+ sd_bus *bus;
int r;
- assert(bus);
-
- if (args[1]) {
- r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &unit);
+ if (argv[1]) {
+ r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &unit);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
@@ -1653,6 +1672,10 @@ static int list_dependencies(sd_bus *bus, char **args) {
pager_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
puts(u);
return list_dependencies_one(bus, u, 0, &units, 0);
@@ -1833,17 +1856,17 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n)
if (streq_ptr(m->state, "degraded")) {
on_state = ansi_highlight_red();
- off_state = ansi_highlight_off();
+ off_state = ansi_normal();
circle = true;
} else if (!streq_ptr(m->state, "running")) {
on_state = ansi_highlight_yellow();
- off_state = ansi_highlight_off();
+ off_state = ansi_normal();
circle = true;
}
if (m->n_failed_units > 0) {
on_failed = ansi_highlight_red();
- off_failed = ansi_highlight_off();
+ off_failed = ansi_normal();
} else
on_failed = off_failed = "";
@@ -1868,12 +1891,11 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n)
printf("\n%u machines listed.\n", n);
}
-static int list_machines(sd_bus *bus, char **args) {
+static int list_machines(int argc, char *argv[], void *userdata) {
struct machine_info *machine_infos = NULL;
+ sd_bus *bus;
int r;
- assert(bus);
-
if (geteuid() != 0) {
log_error("Must be root.");
return -EPERM;
@@ -1881,7 +1903,11 @@ static int list_machines(sd_bus *bus, char **args) {
pager_open_if_enabled();
- r = get_machine_list(bus, &machine_infos, strv_skip_first(args));
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = get_machine_list(bus, &machine_infos, strv_skip(argv, 1));
if (r < 0)
return r;
@@ -1892,13 +1918,13 @@ static int list_machines(sd_bus *bus, char **args) {
return 0;
}
-static int get_default(sd_bus *bus, char **args) {
+static int get_default(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *_path = NULL;
const char *path;
int r;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
r = unit_file_get_default(arg_scope, arg_root, &_path);
if (r < 0)
return log_error_errno(r, "Failed to get default target: %m");
@@ -1906,6 +1932,11 @@ static int get_default(sd_bus *bus, char **args) {
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
r = sd_bus_call_method(
bus,
@@ -1916,10 +1947,8 @@ static int get_default(sd_bus *bus, char **args) {
&error,
&reply,
NULL);
- if (r < 0) {
- log_error("Failed to get default target: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get default target: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &path);
if (r < 0)
@@ -1945,17 +1974,21 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha
}
}
-static int set_default(sd_bus *bus, char **args) {
+static int set_default(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *unit = NULL;
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
int r;
- r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &unit);
+ assert(argc >= 2);
+ assert(argv);
+
+ r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &unit);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
+
r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes);
if (r < 0)
return log_error_errno(r, "Failed to set default target: %m");
@@ -1963,13 +1996,19 @@ static int set_default(sd_bus *bus, char **args) {
if (!arg_quiet)
dump_unit_file_changes(changes, n_changes);
+ unit_file_changes_free(changes, n_changes);
r = 0;
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -1979,10 +2018,8 @@ static int set_default(sd_bus *bus, char **args) {
&error,
&reply,
"sb", unit, 1);
- if (r < 0) {
- log_error("Failed to set default target: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
@@ -1990,13 +2027,11 @@ static int set_default(sd_bus *bus, char **args) {
/* Try to reload if enabled */
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
- unit_file_changes_free(changes, n_changes);
-
return r;
}
@@ -2016,7 +2051,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp
if (n == 0) {
if (!arg_no_legend) {
on = ansi_highlight_green();
- off = ansi_highlight_off();
+ off = ansi_normal();
printf("%sNo jobs %s.%s\n", on, skipped ? "listed" : "running", off);
}
@@ -2057,7 +2092,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp
if (streq(j->state, "running")) {
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -2071,7 +2106,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp
if (!arg_no_legend) {
on = ansi_highlight();
- off = ansi_highlight_off();
+ off = ansi_normal();
printf("\n%s%u jobs listed%s.\n", on, n, off);
}
@@ -2081,17 +2116,24 @@ static bool output_show_job(struct job_info *job, char **patterns) {
return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE);
}
-static int list_jobs(sd_bus *bus, char **args) {
+static int list_jobs(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *name, *type, *state, *job_path, *unit_path;
_cleanup_free_ struct job_info *jobs = NULL;
size_t size = 0;
unsigned c = 0;
+ sd_bus *bus;
uint32_t id;
int r;
bool skipped = false;
+ pager_open_if_enabled();
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -2101,10 +2143,8 @@ static int list_jobs(sd_bus *bus, char **args) {
&error,
&reply,
NULL);
- if (r < 0) {
- log_error("Failed to list jobs: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, 'a', "(usssoo)");
if (r < 0)
@@ -2113,7 +2153,7 @@ static int list_jobs(sd_bus *bus, char **args) {
while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) {
struct job_info job = { id, name, type, state };
- if (!output_show_job(&job, strv_skip_first(args))) {
+ if (!output_show_job(&job, strv_skip(argv, 1))) {
skipped = true;
continue;
}
@@ -2134,18 +2174,21 @@ static int list_jobs(sd_bus *bus, char **args) {
return r;
}
-static int cancel_job(sd_bus *bus, char **args) {
+static int cancel_job(int argc, char *argv[], void *userdata) {
+ sd_bus *bus;
char **name;
int r = 0;
- assert(args);
-
- if (strv_length(args) <= 1)
- return daemon_reload(bus, args);
+ if (argc <= 1)
+ return daemon_reload(argc, argv, userdata);
polkit_agent_open_if_enabled();
- STRV_FOREACH(name, args+1) {
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(name, strv_skip(argv, 1)) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
uint32_t id;
int q;
@@ -2164,7 +2207,7 @@ static int cancel_job(sd_bus *bus, char **args) {
NULL,
"u", id);
if (q < 0) {
- log_error("Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -2217,7 +2260,7 @@ static int need_daemon_reload(sd_bus *bus, const char *unit) {
static void warn_unit_file_changed(const char *name) {
log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
ansi_highlight_red(),
- ansi_highlight_off(),
+ ansi_normal(),
name,
arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
}
@@ -2249,7 +2292,6 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
static int unit_find_paths(
sd_bus *bus,
const char *unit_name,
- bool avoid_bus_cache,
LookupPaths *lp,
char **fragment_path,
char ***dropin_paths) {
@@ -2270,7 +2312,7 @@ static int unit_find_paths(
assert(fragment_path);
assert(lp);
- if (!avoid_bus_cache && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
+ if (!install_client_side() && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *unit_load_error = NULL;
_cleanup_free_ char *unit = NULL;
@@ -2467,10 +2509,8 @@ static int check_triggering_units(
"LoadState",
&error,
&state);
- if (r < 0) {
- log_error("Failed to get load state of %s: %s", n, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get load state of %s: %s", n, bus_error_message(&error, r));
if (streq(state, "masked"))
return 0;
@@ -2483,10 +2523,8 @@ static int check_triggering_units(
"TriggeredBy",
&error,
&triggered_by);
- if (r < 0) {
- log_error("Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r));
STRV_FOREACH(i, triggered_by) {
r = check_one_unit(bus, *i, "active\0reloading\0", true);
@@ -2582,8 +2620,7 @@ static int start_unit_one(
verb = method_to_verb(method);
- log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
- return r;
+ return log_error_errno(r, "Failed to %s %s: %s", verb, name, bus_error_message(error, r));
}
r = sd_bus_message_read(reply, "o", &path);
@@ -2604,11 +2641,13 @@ static int start_unit_one(
}
static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
-
_cleanup_strv_free_ char **mangled = NULL, **globs = NULL;
char **name;
int r, i;
+ assert(bus);
+ assert(ret);
+
STRV_FOREACH(name, names) {
char *t;
@@ -2633,9 +2672,6 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ UnitInfo *unit_infos = NULL;
- if (!bus)
- return log_error_errno(EOPNOTSUPP, "Unit name globbing without bus is not implemented.");
-
r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply);
if (r < 0)
return r;
@@ -2683,24 +2719,28 @@ static enum action verb_to_action(const char *verb) {
return _ACTION_INVALID;
}
-static int start_unit(sd_bus *bus, char **args) {
+static int start_unit(int argc, char *argv[], void *userdata) {
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
const char *method, *mode, *one_name, *suffix = NULL;
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r = 0;
- assert(bus);
-
ask_password_agent_open_if_enabled();
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (arg_action == ACTION_SYSTEMCTL) {
enum action action;
- method = verb_to_method(args[0]);
- action = verb_to_action(args[0]);
- if (streq(args[0], "isolate")) {
+ method = verb_to_method(argv[0]);
+ action = verb_to_action(argv[0]);
+
+ if (streq(argv[0], "isolate")) {
mode = "isolate";
suffix = ".target";
} else
@@ -2720,9 +2760,9 @@ static int start_unit(sd_bus *bus, char **args) {
if (one_name)
names = strv_new(one_name, NULL);
else {
- r = expand_names(bus, args + 1, suffix, &names);
+ r = expand_names(bus, strv_skip(argv, 1), suffix, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
}
if (!arg_no_block) {
@@ -2757,72 +2797,87 @@ static int start_unit(sd_bus *bus, char **args) {
return r;
}
+static int logind_set_wall_message(void) {
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ _cleanup_free_ char *m = NULL;
+ int r;
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ m = strv_join(arg_wall, " ");
+ if (!m)
+ return log_oom();
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetWallMessage",
+ &error,
+ NULL,
+ "sb",
+ m,
+ !arg_no_wall);
+
+ if (r < 0)
+ return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r));
+
+#endif
+ return 0;
+}
+
/* Ask systemd-logind, which might grant access to unprivileged users
* through PolicyKit */
-static int reboot_with_logind(sd_bus *bus, enum action a) {
+static int logind_reboot(enum action a) {
#ifdef HAVE_LOGIND
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- const char *method;
+ const char *method, *description;
+ sd_bus *bus;
int r;
- if (!bus)
- return -EIO;
-
polkit_agent_open_if_enabled();
+ (void) logind_set_wall_message();
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
switch (a) {
case ACTION_REBOOT:
method = "Reboot";
+ description = "reboot system";
break;
case ACTION_POWEROFF:
method = "PowerOff";
+ description = "power off system";
break;
case ACTION_SUSPEND:
method = "Suspend";
+ description = "suspend system";
break;
case ACTION_HIBERNATE:
method = "Hibernate";
+ description = "hibernate system";
break;
case ACTION_HYBRID_SLEEP:
method = "HybridSleep";
+ description = "put system into hybrid sleep";
break;
default:
return -EINVAL;
}
- if (!strv_isempty(arg_wall)) {
- _cleanup_free_ char *m;
-
- m = strv_join(arg_wall, " ");
- if (!m)
- return log_oom();
-
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
- }
-
-
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@@ -2833,27 +2888,25 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
NULL,
"b", arg_ask_password);
if (r < 0)
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
- return r;
+ return 0;
#else
return -ENOSYS;
#endif
}
-static int check_inhibitors(sd_bus *bus, enum action a) {
+static int logind_check_inhibitors(enum action a) {
#ifdef HAVE_LOGIND
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_strv_free_ char **sessions = NULL;
const char *what, *who, *why, *mode;
uint32_t uid, pid;
+ sd_bus *bus;
unsigned c = 0;
char **s;
int r;
- if (!bus)
- return 0;
-
if (arg_ignore_inhibitors || arg_force > 0)
return 0;
@@ -2866,6 +2919,10 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
if (!on_tty())
return 0;
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@@ -2898,10 +2955,11 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
return log_error_errno(ERANGE, "Bad PID %"PRIu32": %m", pid);
if (!strv_contains(sv,
- a == ACTION_HALT ||
- a == ACTION_POWEROFF ||
- a == ACTION_REBOOT ||
- a == ACTION_KEXEC ? "shutdown" : "sleep"))
+ IN_SET(a,
+ ACTION_HALT,
+ ACTION_POWEROFF,
+ ACTION_REBOOT,
+ ACTION_KEXEC) ? "shutdown" : "sleep"))
continue;
get_process_comm(pid, &comm);
@@ -2954,10 +3012,36 @@ static int check_inhibitors(sd_bus *bus, enum action a) {
#endif
}
-static int prepare_firmware_setup(sd_bus *bus) {
+static int logind_prepare_firmware_setup(void) {
#ifdef HAVE_LOGIND
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "SetRebootToFirmwareSetup",
+ &error,
+ NULL,
+ "b", true);
+ if (r < 0)
+ return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
+
+ return 0;
+#else
+ log_error("Cannot remotely indicate to EFI to boot into setup mode.");
+ return -ENOSYS;
#endif
+}
+
+static int prepare_firmware_setup(void) {
int r;
if (!arg_firmware_setup)
@@ -2972,37 +3056,42 @@ static int prepare_firmware_setup(sd_bus *bus) {
return r;
}
-#ifdef HAVE_LOGIND
+ return logind_prepare_firmware_setup();
+}
+
+static int set_exit_code(uint8_t code) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetRebootToFirmwareSetup",
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SetExitCode",
&error,
NULL,
- "b", true);
- if (r < 0) {
- log_error("Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r));
- return r;
- }
+ "y", code);
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
return 0;
-#else
- log_error("Cannot remotely indicate to EFI to boot into setup mode.");
- return -EINVAL;
-#endif
}
-static int start_special(sd_bus *bus, char **args) {
+static int start_special(int argc, char *argv[], void *userdata) {
enum action a;
int r;
- assert(args);
+ assert(argv);
- a = verb_to_action(args[0]);
+ a = verb_to_action(argv[0]);
- r = check_inhibitors(bus, a);
+ r = logind_check_inhibitors(a);
if (r < 0)
return r;
@@ -3011,56 +3100,76 @@ static int start_special(sd_bus *bus, char **args) {
return -EPERM;
}
- r = prepare_firmware_setup(bus);
+ r = prepare_firmware_setup();
if (r < 0)
return r;
- if (a == ACTION_REBOOT && args[1]) {
- r = update_reboot_param_file(args[1]);
+ if (a == ACTION_REBOOT && argc > 1) {
+ r = update_reboot_param_file(argv[1]);
+ if (r < 0)
+ return r;
+
+ } else if (a == ACTION_EXIT && argc > 1) {
+ uint8_t code;
+
+ /* If the exit code is not given on the command line,
+ * don't reset it to zero: just keep it as it might
+ * have been set previously. */
+
+ r = safe_atou8(argv[1], &code);
+ if (r < 0)
+ return log_error_errno(r, "Invalid exit code.");
+
+ r = set_exit_code(code);
if (r < 0)
return r;
}
if (arg_force >= 2 &&
- (a == ACTION_HALT ||
- a == ACTION_POWEROFF ||
- a == ACTION_REBOOT))
+ IN_SET(a,
+ ACTION_HALT,
+ ACTION_POWEROFF,
+ ACTION_REBOOT))
return halt_now(a);
if (arg_force >= 1 &&
- (a == ACTION_HALT ||
- a == ACTION_POWEROFF ||
- a == ACTION_REBOOT ||
- a == ACTION_KEXEC ||
- a == ACTION_EXIT))
- return daemon_reload(bus, args);
-
- /* first try logind, to allow authentication with polkit */
- if (geteuid() != 0 &&
- (a == ACTION_POWEROFF ||
- a == ACTION_REBOOT ||
- a == ACTION_SUSPEND ||
- a == ACTION_HIBERNATE ||
- a == ACTION_HYBRID_SLEEP)) {
- r = reboot_with_logind(bus, a);
- if (r >= 0 || IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ IN_SET(a,
+ ACTION_HALT,
+ ACTION_POWEROFF,
+ ACTION_REBOOT,
+ ACTION_KEXEC,
+ ACTION_EXIT))
+ return daemon_reload(argc, argv, userdata);
+
+ /* First try logind, to allow authentication with polkit */
+ if (IN_SET(a,
+ ACTION_POWEROFF,
+ ACTION_REBOOT,
+ ACTION_SUSPEND,
+ ACTION_HIBERNATE,
+ ACTION_HYBRID_SLEEP)) {
+ r = logind_reboot(a);
+ if (r >= 0)
+ return r;
+ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ /* requested operation is not supported or already in progress */
return r;
- }
- r = start_unit(bus, args);
- if (r == EXIT_SUCCESS)
- warn_wall(a);
+ /* On all other errors, try low-level operation */
+ }
- return r;
+ return start_unit(argc, argv, userdata);
}
-static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) {
+static int check_unit_generic(int code, const char *good_states, char **args) {
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r;
- assert(bus);
- assert(args);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
r = expand_names(bus, args, NULL, &names);
if (r < 0)
@@ -3079,31 +3188,37 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch
return r;
}
-static int check_unit_active(sd_bus *bus, char **args) {
+static int check_unit_active(int argc, char *argv[], void *userdata) {
/* According to LSB: 3, "program is not running" */
- return check_unit_generic(bus, 3, "active\0reloading\0", args + 1);
+ return check_unit_generic(3, "active\0reloading\0", strv_skip(argv, 1));
}
-static int check_unit_failed(sd_bus *bus, char **args) {
- return check_unit_generic(bus, 1, "failed\0", args + 1);
+static int check_unit_failed(int argc, char *argv[], void *userdata) {
+ return check_unit_generic(1, "failed\0", strv_skip(argv, 1));
}
-static int kill_unit(sd_bus *bus, char **args) {
+static int kill_unit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
- char **name;
+ char *kill_who = NULL, **name;
+ sd_bus *bus;
int r, q;
- assert(bus);
- assert(args);
-
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (!arg_kill_who)
arg_kill_who = "all";
- r = expand_names(bus, args + 1, NULL, &names);
+ /* --fail was specified */
+ if (streq(arg_job_mode, "fail"))
+ kill_who = strjoina(arg_kill_who, "-fail", NULL);
+
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -3116,9 +3231,9 @@ static int kill_unit(sd_bus *bus, char **args) {
"KillUnit",
&error,
NULL,
- "ssi", *names, arg_kill_who, arg_signal);
+ "ssi", *names, kill_who ? kill_who : arg_kill_who, arg_signal);
if (q < 0) {
- log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -3283,6 +3398,8 @@ typedef struct UnitStatusInfo {
uint64_t memory_current;
uint64_t memory_limit;
uint64_t cpu_usage_nsec;
+ uint64_t tasks_current;
+ uint64_t tasks_max;
LIST_HEAD(ExecStatusInfo, exec);
} UnitStatusInfo;
@@ -3306,10 +3423,10 @@ static void print_status_info(
if (streq_ptr(i->active_state, "failed")) {
active_on = ansi_highlight_red();
- active_off = ansi_highlight_off();
+ active_off = ansi_normal();
} else if (streq_ptr(i->active_state, "active") || streq_ptr(i->active_state, "reloading")) {
active_on = ansi_highlight_green();
- active_off = ansi_highlight_off();
+ active_off = ansi_normal();
} else
active_on = active_off = "";
@@ -3325,7 +3442,7 @@ static void print_status_info(
if (streq_ptr(i->load_state, "error")) {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -3406,8 +3523,8 @@ static void print_status_info(
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
printf("Condition: start %scondition failed%s at %s%s%s\n",
- ansi_highlight_yellow(), ansi_highlight_off(),
- s2, s1 ? "; " : "", s1 ? s1 : "");
+ ansi_highlight_yellow(), ansi_normal(),
+ s2, s1 ? "; " : "", strempty(s1));
if (i->failed_condition_trigger)
printf(" none of the trigger conditions were met\n");
else if (i->failed_condition)
@@ -3422,8 +3539,8 @@ static void print_status_info(
s2 = format_timestamp(since2, sizeof(since2), i->assert_timestamp);
printf(" Assert: start %sassertion failed%s at %s%s%s\n",
- ansi_highlight_red(), ansi_highlight_off(),
- s2, s1 ? "; " : "", s1 ? s1 : "");
+ ansi_highlight_red(), ansi_normal(),
+ s2, s1 ? "; " : "", strempty(s1));
if (i->failed_assert_trigger)
printf(" none of the trigger assertions were met\n");
else if (i->failed_assert)
@@ -3463,7 +3580,7 @@ static void print_status_info(
good = is_clean_exit_lsb(p->code, p->status, NULL);
if (!good) {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -3541,6 +3658,15 @@ static void print_status_info(
if (i->status_errno > 0)
printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
+ if (i->tasks_current != (uint64_t) -1) {
+ printf(" Tasks: %" PRIu64, i->tasks_current);
+
+ if (i->tasks_max != (uint64_t) -1)
+ printf(" (limit: %" PRIi64 ")\n", i->tasks_max);
+ else
+ printf("\n");
+ }
+
if (i->memory_current != (uint64_t) -1) {
char buf[FORMAT_BYTES_MAX];
@@ -3559,12 +3685,14 @@ static void print_status_info(
if (i->control_group &&
(i->main_pid > 0 || i->control_pid > 0 ||
- ((arg_transport != BUS_TRANSPORT_LOCAL && arg_transport != BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) {
+ (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) {
unsigned c;
printf(" CGroup: %s\n", i->control_group);
- if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_MACHINE) {
+ if (IN_SET(arg_transport,
+ BUS_TRANSPORT_LOCAL,
+ BUS_TRANSPORT_MACHINE)) {
unsigned k = 0;
pid_t extra[2];
static const char prefix[] = " ";
@@ -3774,6 +3902,10 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->memory_current = u;
else if (streq(name, "MemoryLimit"))
i->memory_limit = u;
+ else if (streq(name, "TasksCurrent"))
+ i->tasks_current = u;
+ else if (streq(name, "TasksMax"))
+ i->tasks_max = u;
else if (streq(name, "CPUUsageNSec"))
i->cpu_usage_nsec = u;
@@ -3797,13 +3929,13 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
info->name = strdup(name);
if (!info->name)
- log_oom();
+ return log_oom();
LIST_PREPEND(exec, i->exec, info);
info = new0(ExecStatusInfo, 1);
if (!info)
- log_oom();
+ return log_oom();
}
if (r < 0)
@@ -4250,6 +4382,8 @@ static int show_one(
.memory_current = (uint64_t) -1,
.memory_limit = (uint64_t) -1,
.cpu_usage_nsec = (uint64_t) -1,
+ .tasks_current = (uint64_t) -1,
+ .tasks_max = (uint64_t) -1,
};
ExecStatusInfo *p;
int r;
@@ -4373,10 +4507,8 @@ static int get_unit_dbus_path_by_pid(
&error,
&reply,
"u", pid);
- if (r < 0) {
- log_error("Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
r = sd_bus_message_read(reply, "o", &u);
if (r < 0)
@@ -4447,10 +4579,10 @@ static int show_system_status(sd_bus *bus) {
if (streq_ptr(mi.state, "degraded")) {
on = ansi_highlight_red();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else if (!streq_ptr(mi.state, "running")) {
on = ansi_highlight_yellow();
- off = ansi_highlight_off();
+ off = ansi_normal();
} else
on = off = "";
@@ -4467,7 +4599,9 @@ static int show_system_status(sd_bus *bus) {
format_timestamp_relative(since1, sizeof(since1), mi.timestamp));
printf(" CGroup: %s\n", mi.control_group ?: "/");
- if (arg_transport == BUS_TRANSPORT_LOCAL || arg_transport == BUS_TRANSPORT_MACHINE) {
+ if (IN_SET(arg_transport,
+ BUS_TRANSPORT_LOCAL,
+ BUS_TRANSPORT_MACHINE)) {
static const char prefix[] = " ";
unsigned c;
@@ -4483,16 +4617,22 @@ static int show_system_status(sd_bus *bus) {
return 0;
}
-static int show(sd_bus *bus, char **args) {
- bool show_properties, show_status, new_line = false;
+static int show(int argc, char *argv[], void *userdata) {
+ bool show_properties, show_status, show_help, new_line = false;
bool ellipsized = false;
int r, ret = 0;
+ sd_bus *bus;
- assert(bus);
- assert(args);
+ assert(argv);
+
+ show_properties = streq(argv[0], "show");
+ show_status = streq(argv[0], "status");
+ show_help = streq(argv[0], "help");
- show_properties = streq(args[0], "show");
- show_status = streq(args[0], "status");
+ if (show_help && argc <= 1) {
+ log_error("This command expects one or more unit names. Did you mean --help?");
+ return -EINVAL;
+ }
if (show_properties)
pager_open_if_enabled();
@@ -4503,24 +4643,27 @@ static int show(sd_bus *bus, char **args) {
* be split up into many files. */
setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
- /* If no argument is specified inspect the manager itself */
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
- if (show_properties && strv_length(args) <= 1)
- return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
+ /* If no argument is specified inspect the manager itself */
+ if (show_properties && argc <= 1)
+ return show_one(argv[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
- if (show_status && strv_length(args) <= 1) {
+ if (show_status && argc <= 1) {
pager_open_if_enabled();
show_system_status(bus);
new_line = true;
if (arg_all)
- ret = show_all(args[0], bus, false, &new_line, &ellipsized);
+ ret = show_all(argv[0], bus, false, &new_line, &ellipsized);
} else {
_cleanup_free_ char **patterns = NULL;
char **name;
- STRV_FOREACH(name, args + 1) {
+ STRV_FOREACH(name, strv_skip(argv, 1)) {
_cleanup_free_ char *unit = NULL;
uint32_t id;
@@ -4543,8 +4686,7 @@ static int show(sd_bus *bus, char **args) {
}
}
- r = show_one(args[0], bus, unit, show_properties,
- &new_line, &ellipsized);
+ r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
if (r < 0)
return r;
else if (r > 0 && ret == 0)
@@ -4556,7 +4698,7 @@ static int show(sd_bus *bus, char **args) {
r = expand_names(bus, patterns, NULL, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_free_ char *unit;
@@ -4565,8 +4707,7 @@ static int show(sd_bus *bus, char **args) {
if (!unit)
return log_oom();
- r = show_one(args[0], bus, unit, show_properties,
- &new_line, &ellipsized);
+ r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
if (r < 0)
return r;
else if (r > 0 && ret == 0)
@@ -4620,25 +4761,24 @@ static int cat_file(const char *filename, bool newline) {
newline ? "\n" : "",
ansi_highlight_blue(),
filename,
- ansi_highlight_off());
+ ansi_normal());
fflush(stdout);
return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false);
}
-static int cat(sd_bus *bus, char **args) {
+static int cat(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *user_home = NULL;
_cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
_cleanup_strv_free_ char **names = NULL;
char **name;
- bool first = true, avoid_bus_cache;
+ sd_bus *bus;
+ bool first = true;
int r;
- assert(args);
-
if (arg_transport != BUS_TRANSPORT_LOCAL) {
- log_error("Cannot remotely cat units");
+ log_error("Cannot remotely cat units.");
return -EINVAL;
}
@@ -4646,11 +4786,13 @@ static int cat(sd_bus *bus, char **args) {
if (r < 0)
return r;
- r = expand_names(bus, args + 1, NULL, &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
- return log_error_errno(r, "Failed to expand names: %m");
+ return r;
- avoid_bus_cache = !bus || avoid_bus();
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
+ if (r < 0)
+ return log_error_errno(r, "Failed to expand names: %m");
pager_open_if_enabled();
@@ -4659,7 +4801,7 @@ static int cat(sd_bus *bus, char **args) {
_cleanup_strv_free_ char **dropin_paths = NULL;
char **path;
- r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &fragment_path, &dropin_paths);
+ r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths);
if (r < 0)
return r;
else if (r == 0)
@@ -4686,15 +4828,20 @@ static int cat(sd_bus *bus, char **args) {
return 0;
}
-static int set_property(sd_bus *bus, char **args) {
+static int set_property(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *n = NULL;
+ sd_bus *bus;
char **i;
int r;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -4705,7 +4852,7 @@ static int set_property(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &n);
+ r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &n);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
@@ -4717,7 +4864,7 @@ static int set_property(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- STRV_FOREACH(i, args + 2) {
+ STRV_FOREACH(i, strv_skip(argv, 2)) {
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
if (r < 0)
return bus_log_create_error(r);
@@ -4736,25 +4883,24 @@ static int set_property(sd_bus *bus, char **args) {
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
- if (r < 0) {
- log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r));
return 0;
}
-static int snapshot(sd_bus *bus, char **args) {
+static int snapshot(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *n = NULL, *id = NULL;
const char *path;
+ sd_bus *bus;
int r;
polkit_agent_open_if_enabled();
- if (strv_length(args) > 1) {
- r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
+ if (argc > 1) {
+ r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".snapshot", &n);
if (r < 0)
return log_error_errno(r, "Failed to generate unit name: %m");
} else {
@@ -4763,6 +4909,10 @@ static int snapshot(sd_bus *bus, char **args) {
return log_oom();
}
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -4772,10 +4922,8 @@ static int snapshot(sd_bus *bus, char **args) {
&error,
&reply,
"sb", n, false);
- if (r < 0) {
- log_error("Failed to create snapshot: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create snapshot: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "o", &path);
if (r < 0)
@@ -4789,10 +4937,8 @@ static int snapshot(sd_bus *bus, char **args) {
"Id",
&error,
&id);
- if (r < 0) {
- log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get ID of snapshot: %s", bus_error_message(&error, r));
if (!arg_quiet)
puts(id);
@@ -4800,18 +4946,21 @@ static int snapshot(sd_bus *bus, char **args) {
return 0;
}
-static int delete_snapshot(sd_bus *bus, char **args) {
+static int delete_snapshot(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r;
- assert(args);
-
polkit_agent_open_if_enabled();
- r = expand_names(bus, args + 1, ".snapshot", &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return r;
+
+ r = expand_names(bus, strv_skip(argv, 1), ".snapshot", &names);
+ if (r < 0)
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -4827,7 +4976,7 @@ static int delete_snapshot(sd_bus *bus, char **args) {
NULL,
"s", *name);
if (q < 0) {
- log_error("Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -4836,13 +4985,18 @@ static int delete_snapshot(sd_bus *bus, char **args) {
return r;
}
-static int daemon_reload(sd_bus *bus, char **args) {
+static int daemon_reload(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
const char *method;
+ sd_bus *bus;
int r;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (arg_action == ACTION_RELOAD)
method = "Reload";
else if (arg_action == ACTION_REEXEC)
@@ -4851,15 +5005,15 @@ static int daemon_reload(sd_bus *bus, char **args) {
assert(arg_action == ACTION_SYSTEMCTL);
method =
- streq(args[0], "clear-jobs") ||
- streq(args[0], "cancel") ? "ClearJobs" :
- streq(args[0], "daemon-reexec") ? "Reexecute" :
- streq(args[0], "reset-failed") ? "ResetFailed" :
- streq(args[0], "halt") ? "Halt" :
- streq(args[0], "poweroff") ? "PowerOff" :
- streq(args[0], "reboot") ? "Reboot" :
- streq(args[0], "kexec") ? "KExec" :
- streq(args[0], "exit") ? "Exit" :
+ streq(argv[0], "clear-jobs") ||
+ streq(argv[0], "cancel") ? "ClearJobs" :
+ streq(argv[0], "daemon-reexec") ? "Reexecute" :
+ streq(argv[0], "reset-failed") ? "ResetFailed" :
+ streq(argv[0], "halt") ? "Halt" :
+ streq(argv[0], "poweroff") ? "PowerOff" :
+ streq(argv[0], "reboot") ? "Reboot" :
+ streq(argv[0], "kexec") ? "KExec" :
+ streq(argv[0], "exit") ? "Exit" :
/* "daemon-reload" */ "Reload";
}
@@ -4881,24 +5035,29 @@ static int daemon_reload(sd_bus *bus, char **args) {
* reply */
r = 0;
else if (r < 0)
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
return r < 0 ? r : 0;
}
-static int reset_failed(sd_bus *bus, char **args) {
+static int reset_failed(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
+ sd_bus *bus;
char **name;
int r, q;
- if (strv_length(args) <= 1)
- return daemon_reload(bus, args);
+ if (argc <= 1)
+ return daemon_reload(argc, argv, userdata);
polkit_agent_open_if_enabled();
- r = expand_names(bus, args + 1, NULL, &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
- log_error_errno(r, "Failed to expand names: %m");
+ return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -4913,7 +5072,7 @@ static int reset_failed(sd_bus *bus, char **args) {
NULL,
"s", *name);
if (q < 0) {
- log_error("Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
+ log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q));
if (r == 0)
r = q;
}
@@ -4922,14 +5081,19 @@ static int reset_failed(sd_bus *bus, char **args) {
return r;
}
-static int show_environment(sd_bus *bus, char **args) {
+static int show_environment(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *text;
+ sd_bus *bus;
int r;
pager_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
@@ -4939,10 +5103,8 @@ static int show_environment(sd_bus *bus, char **args) {
&error,
&reply,
"as");
- if (r < 0) {
- log_error("Failed to get environment: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r));
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s");
if (r < 0)
@@ -4960,23 +5122,27 @@ static int show_environment(sd_bus *bus, char **args) {
return 0;
}
-static int switch_root(sd_bus *bus, char **args) {
+static int switch_root(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *cmdline_init = NULL;
const char *root, *init;
- unsigned l;
+ sd_bus *bus;
int r;
- l = strv_length(args);
- if (l < 2 || l > 3) {
+ if (arg_transport != BUS_TRANSPORT_LOCAL) {
+ log_error("Cannot switch root remotely.");
+ return -EINVAL;
+ }
+
+ if (argc < 2 || argc > 3) {
log_error("Wrong number of arguments.");
return -EINVAL;
}
- root = args[1];
+ root = argv[1];
- if (l >= 3)
- init = args[2];
+ if (argc >= 3)
+ init = argv[2];
else {
r = parse_env_file("/proc/cmdline", WHITESPACE,
"init", &cmdline_init,
@@ -5002,6 +5168,10 @@ static int switch_root(sd_bus *bus, char **args) {
init = NULL;
}
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
log_debug("Switching root - root: %s; init: %s", root, strna(init));
r = sd_bus_call_method(
@@ -5013,26 +5183,29 @@ static int switch_root(sd_bus *bus, char **args) {
&error,
NULL,
"ss", root, init);
- if (r < 0) {
- log_error("Failed to switch root: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
return 0;
}
-static int set_environment(sd_bus *bus, char **args) {
+static int set_environment(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
const char *method;
+ sd_bus *bus;
int r;
- assert(bus);
- assert(args);
+ assert(argc > 1);
+ assert(argv);
polkit_agent_open_if_enabled();
- method = streq(args[0], "set-environment")
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ method = streq(argv[0], "set-environment")
? "SetEnvironment"
: "UnsetEnvironment";
@@ -5046,29 +5219,29 @@ static int set_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- r = sd_bus_message_append_strv(m, args + 1);
+ r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
- if (r < 0) {
- log_error("Failed to set environment: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r));
return 0;
}
-static int import_environment(sd_bus *bus, char **args) {
+static int import_environment(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
+ sd_bus *bus;
int r;
- assert(bus);
- assert(args);
-
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -5079,7 +5252,7 @@ static int import_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- if (strv_isempty(args + 1))
+ if (argc < 2)
r = sd_bus_message_append_strv(m, environ);
else {
char **a, **b;
@@ -5088,7 +5261,7 @@ static int import_environment(sd_bus *bus, char **args) {
if (r < 0)
return bus_log_create_error(r);
- STRV_FOREACH(a, args + 1) {
+ STRV_FOREACH(a, strv_skip(argv, 1)) {
if (!env_name_is_valid(*a)) {
log_error("Not a valid environment variable name: %s", *a);
@@ -5116,10 +5289,8 @@ static int import_environment(sd_bus *bus, char **args) {
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, NULL);
- if (r < 0) {
- log_error("Failed to import environment: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r));
return 0;
}
@@ -5134,9 +5305,10 @@ static int enable_sysv_units(const char *verb, char **args) {
if (arg_scope != UNIT_FILE_SYSTEM)
return 0;
- if (!streq(verb, "enable") &&
- !streq(verb, "disable") &&
- !streq(verb, "is-enabled"))
+ if (!STR_IN_SET(verb,
+ "enable",
+ "disable",
+ "is-enabled"))
return 0;
/* Processes all SysV units, and reshuffles the array so that
@@ -5221,13 +5393,13 @@ static int enable_sysv_units(const char *verb, char **args) {
(void) reset_signal_mask();
execv(argv[0], (char**) argv);
- log_error("Failed to execute %s: %m", argv[0]);
+ log_error_errno(r, "Failed to execute %s: %m", argv[0]);
_exit(EXIT_FAILURE);
}
j = wait_for_terminate(pid, &status);
if (j < 0) {
- log_error_errno(r, "Failed to wait for child: %m");
+ log_error_errno(j, "Failed to wait for child: %m");
return j;
}
@@ -5297,18 +5469,18 @@ static int mangle_names(char **original_names, char ***mangled_names) {
return 0;
}
-static int enable_unit(sd_bus *bus, char **args) {
+static int enable_unit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
- const char *verb = args[0];
+ const char *verb = argv[0];
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
int carries_install_info = -1;
int r;
- if (!args[1])
+ if (!argv[1])
return 0;
- r = mangle_names(args+1, &names);
+ r = mangle_names(strv_skip(argv, 1), &names);
if (r < 0)
return r;
@@ -5321,7 +5493,7 @@ static int enable_unit(sd_bus *bus, char **args) {
if (strv_isempty(names))
return 0;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
if (streq(verb, "enable")) {
r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
carries_install_info = r;
@@ -5357,9 +5529,14 @@ static int enable_unit(sd_bus *bus, char **args) {
int expect_carries_install_info = false;
bool send_force = true, send_preset_mode = false;
const char *method;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
if (streq(verb, "enable")) {
method = "EnableUnitFiles";
expect_carries_install_info = true;
@@ -5419,10 +5596,8 @@ static int enable_unit(sd_bus *bus, char **args) {
}
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
if (expect_carries_install_info) {
r = sd_bus_message_read(reply, "b", &carries_install_info);
@@ -5436,7 +5611,7 @@ static int enable_unit(sd_bus *bus, char **args) {
/* Try to reload if enabled */
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
@@ -5452,16 +5627,21 @@ static int enable_unit(sd_bus *bus, char **args) {
"3) A unit may be started when needed via activation (socket, path, timer,\n"
" D-Bus, udev, scripted systemctl call, ...).\n");
- if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) {
+ if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
char *new_args[n_changes + 2];
+ sd_bus *bus;
unsigned i;
- new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop";
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop");
for (i = 0; i < n_changes; i++)
new_args[i + 1] = basename(changes[i].path);
new_args[i + 1] = NULL;
- r = start_unit(bus, new_args);
+ r = start_unit(strv_length(new_args), new_args, userdata);
}
finish:
@@ -5470,21 +5650,21 @@ finish:
return r;
}
-static int add_dependency(sd_bus *bus, char **args) {
+static int add_dependency(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
_cleanup_free_ char *target = NULL;
- const char *verb = args[0];
+ const char *verb = argv[0];
UnitDependency dep;
int r = 0;
- if (!args[1])
+ if (!argv[1])
return 0;
- r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &target);
+ r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &target);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
- r = mangle_names(args+2, &names);
+ r = mangle_names(strv_skip(argv, 2), &names);
if (r < 0)
return r;
@@ -5495,7 +5675,7 @@ static int add_dependency(sd_bus *bus, char **args) {
else
assert_not_reached("Unknown verb");
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
@@ -5512,9 +5692,14 @@ static int add_dependency(sd_bus *bus, char **args) {
} else {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -5534,17 +5719,15 @@ static int add_dependency(sd_bus *bus, char **args) {
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
@@ -5552,12 +5735,12 @@ static int add_dependency(sd_bus *bus, char **args) {
return r;
}
-static int preset_all(sd_bus *bus, char **args) {
+static int preset_all(int argc, char *argv[], void *userdata) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
int r;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes);
if (r < 0) {
@@ -5573,9 +5756,14 @@ static int preset_all(sd_bus *bus, char **args) {
} else {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
+ sd_bus *bus;
polkit_agent_open_if_enabled();
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -5588,17 +5776,15 @@ static int preset_all(sd_bus *bus, char **args) {
unit_file_preset_mode_to_string(arg_preset_mode),
arg_runtime,
arg_force);
- if (r < 0) {
- log_error("Failed to execute operation: %s", bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
if (!arg_no_reload)
- r = daemon_reload(bus, args);
+ r = daemon_reload(argc, argv, userdata);
else
r = 0;
}
@@ -5609,25 +5795,24 @@ finish:
return r;
}
-static int unit_is_enabled(sd_bus *bus, char **args) {
+static int unit_is_enabled(int argc, char *argv[], void *userdata) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_strv_free_ char **names = NULL;
bool enabled;
char **name;
int r;
- r = mangle_names(args+1, &names);
+ r = mangle_names(strv_skip(argv, 1), &names);
if (r < 0)
return r;
- r = enable_sysv_units(args[0], names);
+ r = enable_sysv_units(argv[0], names);
if (r < 0)
return r;
enabled = r > 0;
- if (!bus || avoid_bus()) {
+ if (install_client_side()) {
STRV_FOREACH(name, names) {
UnitFileState state;
@@ -5636,10 +5821,11 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
if (state < 0)
return log_error_errno(state, "Failed to get unit file state for %s: %m", *name);
- if (state == UNIT_FILE_ENABLED ||
- state == UNIT_FILE_ENABLED_RUNTIME ||
- state == UNIT_FILE_STATIC ||
- state == UNIT_FILE_INDIRECT)
+ if (IN_SET(state,
+ UNIT_FILE_ENABLED,
+ UNIT_FILE_ENABLED_RUNTIME,
+ UNIT_FILE_STATIC,
+ UNIT_FILE_INDIRECT))
enabled = true;
if (!arg_quiet)
@@ -5647,6 +5833,13 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
}
} else {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
STRV_FOREACH(name, names) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
const char *s;
@@ -5660,10 +5853,8 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
&error,
&reply,
"s", *name);
- if (r < 0) {
- log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &s);
if (r < 0)
@@ -5680,10 +5871,21 @@ static int unit_is_enabled(sd_bus *bus, char **args) {
return !enabled;
}
-static int is_system_running(sd_bus *bus, char **args) {
+static int is_system_running(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *state = NULL;
+ sd_bus *bus;
int r;
+ if (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted()) {
+ if (!arg_quiet)
+ puts("offline");
+ return EXIT_FAILURE;
+ }
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
r = sd_bus_get_property_string(
bus,
"org.freedesktop.systemd1",
@@ -5705,7 +5907,7 @@ static int is_system_running(sd_bus *bus, char **args) {
}
static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) {
- char *t;
+ _cleanup_free_ char *t = NULL;
int r;
assert(new_path);
@@ -5717,27 +5919,21 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path);
r = mkdir_parents(new_path, 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
- free(t);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
r = copy_file(original_path, t, 0, 0644, 0);
if (r == -ENOENT) {
+
r = touch(t);
- if (r < 0) {
- log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
- free(t);
- return r;
- }
- } else if (r < 0) {
- log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
- free(t);
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
+
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
*ret_tmp_fn = t;
+ t = NULL;
return 0;
}
@@ -5745,6 +5941,9 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
_cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
+ assert(name);
+ assert(ret_path);
+
switch (arg_scope) {
case UNIT_FILE_SYSTEM:
path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
@@ -5775,12 +5974,16 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
return log_oom();
if (arg_runtime) {
- if (access(path, F_OK) >= 0)
- return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
- run, path);
- if (path2 && access(path2, F_OK) >= 0)
- return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.",
- run, path2);
+ if (access(path, F_OK) >= 0) {
+ log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
+ return -EEXIST;
+ }
+
+ if (path2 && access(path2, F_OK) >= 0) {
+ log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path2);
+ return -EEXIST;
+ }
+
*ret_path = run;
run = NULL;
} else {
@@ -5792,8 +5995,7 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
}
static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
- char *tmp_new_path, *ending;
- char *tmp_tmp_path;
+ char *tmp_new_path, *tmp_tmp_path, *ending;
int r;
assert(unit_name);
@@ -5825,8 +6027,7 @@ static int unit_file_create_copy(
char **ret_new_path,
char **ret_tmp_path) {
- char *tmp_new_path;
- char *tmp_tmp_path;
+ char *tmp_new_path, *tmp_tmp_path;
int r;
assert(fragment_path);
@@ -5873,10 +6074,8 @@ static int run_editor(char **paths) {
assert(paths);
pid = fork();
- if (pid < 0) {
- log_error_errno(errno, "Failed to fork: %m");
- return -errno;
- }
+ if (pid < 0)
+ return log_error_errno(errno, "Failed to fork: %m");
if (pid == 0) {
const char **args;
@@ -5934,7 +6133,7 @@ static int run_editor(char **paths) {
* failing.
*/
if (errno != ENOENT) {
- log_error("Failed to execute %s: %m", editor);
+ log_error_errno(errno, "Failed to execute %s: %m", editor);
_exit(EXIT_FAILURE);
}
}
@@ -5947,14 +6146,13 @@ static int run_editor(char **paths) {
if (r < 0)
return log_error_errno(r, "Failed to wait for child: %m");
- return r;
+ return 0;
}
static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
_cleanup_free_ char *user_home = NULL;
_cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
- bool avoid_bus_cache;
char **name;
int r;
@@ -5965,13 +6163,11 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
if (r < 0)
return r;
- avoid_bus_cache = !bus || avoid_bus();
-
STRV_FOREACH(name, names) {
_cleanup_free_ char *path = NULL;
char *new_path, *tmp_path;
- r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &path, NULL);
+ r = unit_find_paths(bus, *name, &lp, &path, NULL);
if (r < 0)
return r;
else if (r == 0)
@@ -5997,25 +6193,28 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
return 0;
}
-static int edit(sd_bus *bus, char **args) {
+static int edit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
_cleanup_strv_free_ char **paths = NULL;
char **original, **tmp;
+ sd_bus *bus;
int r;
- assert(args);
-
if (!on_tty()) {
- log_error("Cannot edit units if not on a tty");
+ log_error("Cannot edit units if not on a tty.");
return -EINVAL;
}
if (arg_transport != BUS_TRANSPORT_LOCAL) {
- log_error("Cannot remotely edit units");
+ log_error("Cannot edit units remotely.");
return -EINVAL;
}
- r = expand_names(bus, args + 1, NULL, &names);
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
@@ -6031,13 +6230,14 @@ static int edit(sd_bus *bus, char **args) {
goto end;
STRV_FOREACH_PAIR(original, tmp, paths) {
- /* If the temporary file is empty we ignore it.
- * It's useful if the user wants to cancel its modification
+ /* If the temporary file is empty we ignore it. It's
+ * useful if the user wants to cancel its modification
*/
if (null_or_empty_path(*tmp)) {
- log_warning("Editing \"%s\" canceled: temporary file is empty", *original);
+ log_warning("Editing \"%s\" canceled: temporary file is empty.", *original);
continue;
}
+
r = rename(*tmp, *original);
if (r < 0) {
r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original);
@@ -6045,12 +6245,14 @@ static int edit(sd_bus *bus, char **args) {
}
}
- if (!arg_no_reload && bus && !avoid_bus())
- r = daemon_reload(bus, args);
+ r = 0;
+
+ if (!arg_no_reload && !install_client_side())
+ r = daemon_reload(argc, argv, userdata);
end:
STRV_FOREACH_PAIR(original, tmp, paths)
- unlink_noerrno(*tmp);
+ (void) unlink(*tmp);
return r;
}
@@ -6180,7 +6382,7 @@ static void systemctl_help(void) {
" poweroff Shut down and power-off the system\n"
" reboot [ARG] Shut down and reboot the system\n"
" kexec Shut down and reboot the system with kexec\n"
- " exit Request user instance exit\n"
+ " exit [EXIT_CODE] Request user instance or container exit\n"
" switch-root ROOT [INIT] Change to a different root file system\n"
" suspend Suspend the system\n"
" hibernate Hibernate the system\n"
@@ -6244,15 +6446,90 @@ static void runlevel_help(void) {
static void help_types(void) {
int i;
- const char *t;
if (!arg_no_legend)
puts("Available unit types:");
- for (i = 0; i < _UNIT_TYPE_MAX; i++) {
- t = unit_type_to_string(i);
- if (t)
- puts(t);
- }
+ for (i = 0; i < _UNIT_TYPE_MAX; i++)
+ puts(unit_type_to_string(i));
+}
+
+static void help_states(void) {
+ int i;
+
+ if (!arg_no_legend)
+ puts("Available unit load states:");
+ for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++)
+ puts(unit_load_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable unit active states:");
+ for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++)
+ puts(unit_active_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable automount unit substates:");
+ for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++)
+ puts(automount_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable busname unit substates:");
+ for (i = 0; i < _BUSNAME_STATE_MAX; i++)
+ puts(busname_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable device unit substates:");
+ for (i = 0; i < _DEVICE_STATE_MAX; i++)
+ puts(device_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable mount unit substates:");
+ for (i = 0; i < _MOUNT_STATE_MAX; i++)
+ puts(mount_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable path unit substates:");
+ for (i = 0; i < _PATH_STATE_MAX; i++)
+ puts(path_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable scope unit substates:");
+ for (i = 0; i < _SCOPE_STATE_MAX; i++)
+ puts(scope_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable service unit substates:");
+ for (i = 0; i < _SERVICE_STATE_MAX; i++)
+ puts(service_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable slice unit substates:");
+ for (i = 0; i < _SLICE_STATE_MAX; i++)
+ puts(slice_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable snapshot unit substates:");
+ for (i = 0; i < _SNAPSHOT_STATE_MAX; i++)
+ puts(snapshot_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable socket unit substates:");
+ for (i = 0; i < _SOCKET_STATE_MAX; i++)
+ puts(socket_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable swap unit substates:");
+ for (i = 0; i < _SWAP_STATE_MAX; i++)
+ puts(swap_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable target unit substates:");
+ for (i = 0; i < _TARGET_STATE_MAX; i++)
+ puts(target_state_to_string(i));
+
+ if (!arg_no_legend)
+ puts("\nAvailable timer unit substates:");
+ for (i = 0; i < _TIMER_STATE_MAX; i++)
+ puts(timer_state_to_string(i));
}
static int systemctl_parse_argv(int argc, char *argv[]) {
@@ -6340,6 +6617,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
+ /* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
+ arg_ask_password = true;
+
while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir", options, NULL)) >= 0)
switch (c) {
@@ -6349,9 +6629,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 't': {
const char *word, *state;
@@ -6370,7 +6648,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
}
if (unit_type_from_string(type) >= 0) {
- if (strv_push(&arg_types, type))
+ if (strv_push(&arg_types, type) < 0)
return log_oom();
type = NULL;
continue;
@@ -6380,7 +6658,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
* load states, but let's support this
* in --types= too for compatibility
* with old versions */
- if (unit_load_state_from_string(optarg) >= 0) {
+ if (unit_load_state_from_string(type) >= 0) {
if (strv_push(&arg_states, type) < 0)
return log_oom();
type = NULL;
@@ -6525,7 +6803,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case 's':
- if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) {
+ arg_signal = signal_from_string_try_harder(optarg);
+ if (arg_signal < 0) {
log_error("Failed to parse signal string %s.", optarg);
return -EINVAL;
}
@@ -6581,14 +6860,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
size_t size;
FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
- char *s;
+ _cleanup_free_ char *s = NULL;
s = strndup(word, size);
if (!s)
return log_oom();
- if (strv_consume(&arg_states, s) < 0)
+ if (streq(s, "help")) {
+ help_states();
+ return 0;
+ }
+
+ if (strv_push(&arg_states, s) < 0)
return log_oom();
+
+ s = NULL;
}
break;
}
@@ -6727,7 +7013,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
return 1;
}
-static int parse_time_spec(const char *t, usec_t *_u) {
+static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
assert(t);
assert(_u);
@@ -6793,12 +7079,13 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
{}
};
+ char **wall = NULL;
int c, r;
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "HPrhkKt:afFc", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "HPrhkKtafFc", options, NULL)) >= 0)
switch (c) {
case ARG_HELP:
@@ -6856,7 +7143,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
}
if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) {
- r = parse_time_spec(argv[optind], &arg_when);
+ r = parse_shutdown_time_spec(argv[optind], &arg_when);
if (r < 0) {
log_error("Failed to parse time specification: %s", argv[optind]);
return r;
@@ -6866,10 +7153,16 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN)
/* No time argument for shutdown cancel */
- arg_wall = argv + optind;
+ wall = argv + optind;
else if (argc > optind + 1)
/* We skip the time argument */
- arg_wall = argv + optind + 1;
+ wall = argv + optind + 1;
+
+ if (wall) {
+ arg_wall = strv_copy(wall);
+ if (!arg_wall)
+ return log_oom();
+ }
optind = argc;
@@ -6933,8 +7226,7 @@ static int telinit_parse_argv(int argc, char *argv[]) {
}
if (optind >= argc) {
- log_error("%s: required argument missing.",
- program_invocation_short_name);
+ log_error("%s: required argument missing.", program_invocation_short_name);
return -EINVAL;
}
@@ -7069,7 +7361,7 @@ _pure_ static int action_to_runlevel(void) {
}
static int talk_initctl(void) {
-
+#ifdef HAVE_SYSV_COMPAT
struct init_request request = {
.magic = INIT_MAGIC,
.sleeptime = 0,
@@ -7091,8 +7383,7 @@ static int talk_initctl(void) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
- return -errno;
+ return log_error_errno(errno, "Failed to open "INIT_FIFO": %m");
}
r = loop_write(fd, &request, sizeof(request), false);
@@ -7100,177 +7391,91 @@ static int talk_initctl(void) {
return log_error_errno(r, "Failed to write to "INIT_FIFO": %m");
return 1;
+#else
+ return 0;
+#endif
}
-static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
-
- static const struct {
- const char* verb;
- const enum {
- MORE,
- LESS,
- EQUAL
- } argc_cmp;
- const int argc;
- int (* const dispatch)(sd_bus *bus, char **args);
- const enum {
- NOBUS = 1,
- FORCE,
- } bus;
- } verbs[] = {
- { "list-units", MORE, 0, list_units },
- { "list-unit-files", MORE, 1, list_unit_files, NOBUS },
- { "list-sockets", MORE, 1, list_sockets },
- { "list-timers", MORE, 1, list_timers },
- { "list-jobs", MORE, 1, list_jobs },
- { "list-machines", MORE, 1, list_machines },
- { "clear-jobs", EQUAL, 1, daemon_reload },
- { "cancel", MORE, 2, cancel_job },
- { "start", MORE, 2, start_unit },
- { "stop", MORE, 2, start_unit },
- { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
- { "reload", MORE, 2, start_unit },
- { "restart", MORE, 2, start_unit },
- { "try-restart", MORE, 2, start_unit },
- { "reload-or-restart", MORE, 2, start_unit },
- { "reload-or-try-restart", MORE, 2, start_unit },
- { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */
- { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
- { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */
- { "isolate", EQUAL, 2, start_unit },
- { "kill", MORE, 2, kill_unit },
- { "is-active", MORE, 2, check_unit_active },
- { "check", MORE, 2, check_unit_active },
- { "is-failed", MORE, 2, check_unit_failed },
- { "show", MORE, 1, show },
- { "cat", MORE, 2, cat, NOBUS },
- { "status", MORE, 1, show },
- { "help", MORE, 2, show },
- { "snapshot", LESS, 2, snapshot },
- { "delete", MORE, 2, delete_snapshot },
- { "daemon-reload", EQUAL, 1, daemon_reload },
- { "daemon-reexec", EQUAL, 1, daemon_reload },
- { "show-environment", EQUAL, 1, show_environment },
- { "set-environment", MORE, 2, set_environment },
- { "unset-environment", MORE, 2, set_environment },
- { "import-environment", MORE, 1, import_environment},
- { "halt", EQUAL, 1, start_special, FORCE },
- { "poweroff", EQUAL, 1, start_special, FORCE },
- { "reboot", MORE, 1, start_special, FORCE },
- { "kexec", EQUAL, 1, start_special },
- { "suspend", EQUAL, 1, start_special },
- { "hibernate", EQUAL, 1, start_special },
- { "hybrid-sleep", EQUAL, 1, start_special },
- { "default", EQUAL, 1, start_special },
- { "rescue", EQUAL, 1, start_special },
- { "emergency", EQUAL, 1, start_special },
- { "exit", EQUAL, 1, start_special },
- { "reset-failed", MORE, 1, reset_failed },
- { "enable", MORE, 2, enable_unit, NOBUS },
- { "disable", MORE, 2, enable_unit, NOBUS },
- { "is-enabled", MORE, 2, unit_is_enabled, NOBUS },
- { "reenable", MORE, 2, enable_unit, NOBUS },
- { "preset", MORE, 2, enable_unit, NOBUS },
- { "preset-all", EQUAL, 1, preset_all, NOBUS },
- { "mask", MORE, 2, enable_unit, NOBUS },
- { "unmask", MORE, 2, enable_unit, NOBUS },
- { "link", MORE, 2, enable_unit, NOBUS },
- { "switch-root", MORE, 2, switch_root },
- { "list-dependencies", LESS, 2, list_dependencies },
- { "set-default", EQUAL, 2, set_default, NOBUS },
- { "get-default", EQUAL, 1, get_default, NOBUS },
- { "set-property", MORE, 3, set_property },
- { "is-system-running", EQUAL, 1, is_system_running },
- { "add-wants", MORE, 3, add_dependency, NOBUS },
- { "add-requires", MORE, 3, add_dependency, NOBUS },
- { "edit", MORE, 2, edit, NOBUS },
+static int systemctl_main(int argc, char *argv[]) {
+
+ static const Verb verbs[] = {
+ { "list-units", VERB_ANY, 1, VERB_DEFAULT, list_units },
+ { "list-unit-files", VERB_ANY, 1, 0, list_unit_files },
+ { "list-sockets", VERB_ANY, 1, 0, list_sockets },
+ { "list-timers", VERB_ANY, 1, 0, list_timers },
+ { "list-jobs", VERB_ANY, 1, 0, list_jobs },
+ { "list-machines", VERB_ANY, 1, 0, list_machines },
+ { "clear-jobs", VERB_ANY, 1, 0, daemon_reload },
+ { "cancel", 2, VERB_ANY, 0, cancel_job },
+ { "start", 2, VERB_ANY, 0, start_unit },
+ { "stop", 2, VERB_ANY, 0, start_unit },
+ { "condstop", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */
+ { "reload", 2, VERB_ANY, 0, start_unit },
+ { "restart", 2, VERB_ANY, 0, start_unit },
+ { "try-restart", 2, VERB_ANY, 0, start_unit },
+ { "reload-or-restart", 2, VERB_ANY, 0, start_unit },
+ { "reload-or-try-restart", 2, VERB_ANY, 0, start_unit },
+ { "force-reload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with SysV */
+ { "condreload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */
+ { "condrestart", 2, VERB_ANY, 0, start_unit }, /* For compatibility with RH */
+ { "isolate", 2, 2, 0, start_unit },
+ { "kill", 2, VERB_ANY, 0, kill_unit },
+ { "is-active", 2, VERB_ANY, 0, check_unit_active },
+ { "check", 2, VERB_ANY, 0, check_unit_active },
+ { "is-failed", 2, VERB_ANY, 0, check_unit_failed },
+ { "show", VERB_ANY, VERB_ANY, 0, show },
+ { "cat", 2, VERB_ANY, 0, cat },
+ { "status", VERB_ANY, VERB_ANY, 0, show },
+ { "help", VERB_ANY, VERB_ANY, 0, show },
+ { "snapshot", VERB_ANY, 2, 0, snapshot },
+ { "delete", 2, VERB_ANY, 0, delete_snapshot },
+ { "daemon-reload", VERB_ANY, 1, 0, daemon_reload },
+ { "daemon-reexec", VERB_ANY, 1, 0, daemon_reload },
+ { "show-environment", VERB_ANY, 1, 0, show_environment },
+ { "set-environment", 2, VERB_ANY, 0, set_environment },
+ { "unset-environment", 2, VERB_ANY, 0, set_environment },
+ { "import-environment", VERB_ANY, VERB_ANY, 0, import_environment},
+ { "halt", VERB_ANY, 1, 0, start_special },
+ { "poweroff", VERB_ANY, 1, 0, start_special },
+ { "reboot", VERB_ANY, 2, 0, start_special },
+ { "kexec", VERB_ANY, 1, 0, start_special },
+ { "suspend", VERB_ANY, 1, 0, start_special },
+ { "hibernate", VERB_ANY, 1, 0, start_special },
+ { "hybrid-sleep", VERB_ANY, 1, 0, start_special },
+ { "default", VERB_ANY, 1, 0, start_special },
+ { "rescue", VERB_ANY, 1, 0, start_special },
+ { "emergency", VERB_ANY, 1, 0, start_special },
+ { "exit", VERB_ANY, 2, 0, start_special },
+ { "reset-failed", VERB_ANY, VERB_ANY, 0, reset_failed },
+ { "enable", 2, VERB_ANY, 0, enable_unit },
+ { "disable", 2, VERB_ANY, 0, enable_unit },
+ { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
+ { "reenable", 2, VERB_ANY, 0, enable_unit },
+ { "preset", 2, VERB_ANY, 0, enable_unit },
+ { "preset-all", VERB_ANY, 1, 0, preset_all },
+ { "mask", 2, VERB_ANY, 0, enable_unit },
+ { "unmask", 2, VERB_ANY, 0, enable_unit },
+ { "link", 2, VERB_ANY, 0, enable_unit },
+ { "switch-root", 2, VERB_ANY, 0, switch_root },
+ { "list-dependencies", VERB_ANY, 2, 0, list_dependencies },
+ { "set-default", 2, 2, 0, set_default },
+ { "get-default", VERB_ANY, 1, 0, get_default, },
+ { "set-property", 3, VERB_ANY, 0, set_property },
+ { "is-system-running", VERB_ANY, 1, 0, is_system_running },
+ { "add-wants", 3, VERB_ANY, 0, add_dependency },
+ { "add-requires", 3, VERB_ANY, 0, add_dependency },
+ { "edit", 2, VERB_ANY, 0, edit },
{}
- }, *verb = verbs;
-
- int left;
-
- assert(argc >= 0);
- assert(argv);
-
- left = argc - optind;
-
- /* Special rule: no arguments (left == 0) means "list-units" */
- if (left > 0) {
- if (streq(argv[optind], "help") && !argv[optind+1]) {
- log_error("This command expects one or more "
- "unit names. Did you mean --help?");
- return -EINVAL;
- }
-
- for (; verb->verb; verb++)
- if (streq(argv[optind], verb->verb))
- goto found;
-
- log_error("Unknown operation '%s'.", argv[optind]);
- return -EINVAL;
- }
-found:
-
- switch (verb->argc_cmp) {
-
- case EQUAL:
- if (left != verb->argc) {
- log_error("Invalid number of arguments.");
- return -EINVAL;
- }
-
- break;
-
- case MORE:
- if (left < verb->argc) {
- log_error("Too few arguments.");
- return -EINVAL;
- }
-
- break;
-
- case LESS:
- if (left > verb->argc) {
- log_error("Too many arguments.");
- return -EINVAL;
- }
-
- break;
-
- default:
- assert_not_reached("Unknown comparison operator.");
- }
-
- /* Require a bus connection for all operations but
- * enable/disable */
- if (verb->bus == NOBUS) {
- if (!bus && !avoid_bus()) {
- log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
- return -EIO;
- }
-
- } else {
- if (running_in_chroot() > 0) {
- log_info("Running in chroot, ignoring request.");
- return 0;
- }
-
- if ((verb->bus != FORCE || arg_force <= 0) && !bus) {
- log_error_errno(bus_error, "Failed to get D-Bus connection: %m");
- return -EIO;
- }
- }
+ };
- return verb->dispatch(bus, argv + optind);
+ return dispatch_verb(argc, argv, verbs, NULL);
}
-static int reload_with_fallback(sd_bus *bus) {
+static int reload_with_fallback(void) {
- if (bus) {
- /* First, try systemd via D-Bus. */
- if (daemon_reload(bus, NULL) >= 0)
- return 0;
- }
+ /* First, try systemd via D-Bus. */
+ if (daemon_reload(0, NULL, NULL) >= 0)
+ return 0;
/* Nothing else worked, so let's try signals */
assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
@@ -7281,25 +7486,19 @@ static int reload_with_fallback(sd_bus *bus) {
return 0;
}
-static int start_with_fallback(sd_bus *bus) {
+static int start_with_fallback(void) {
- if (bus) {
- /* First, try systemd via D-Bus. */
- if (start_unit(bus, NULL) >= 0)
- goto done;
- }
+ /* First, try systemd via D-Bus. */
+ if (start_unit(0, NULL, NULL) >= 0)
+ return 0;
/* Nothing else worked, so let's try
* /dev/initctl */
if (talk_initctl() > 0)
- goto done;
+ return 0;
log_error("Failed to talk to init daemon.");
return -EIO;
-
-done:
- warn_wall(arg_action);
- return 0;
}
static int halt_now(enum action a) {
@@ -7307,22 +7506,22 @@ static int halt_now(enum action a) {
/* The kernel will automaticall flush ATA disks and suchlike
* on reboot(), but the file systems need to be synce'd
* explicitly in advance. */
- sync();
+ (void) sync();
/* Make sure C-A-D is handled by the kernel from this point
* on... */
- reboot(RB_ENABLE_CAD);
+ (void) reboot(RB_ENABLE_CAD);
switch (a) {
case ACTION_HALT:
log_info("Halting.");
- reboot(RB_HALT_SYSTEM);
+ (void) reboot(RB_HALT_SYSTEM);
return -errno;
case ACTION_POWEROFF:
log_info("Powering off.");
- reboot(RB_POWER_OFF);
+ (void) reboot(RB_POWER_OFF);
return -errno;
case ACTION_KEXEC:
@@ -7331,12 +7530,11 @@ static int halt_now(enum action a) {
if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
log_info("Rebooting with argument '%s'.", param);
- syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, param);
+ (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
}
log_info("Rebooting.");
- reboot(RB_AUTOBOOT);
+ (void) reboot(RB_AUTOBOOT);
return -errno;
}
@@ -7345,111 +7543,101 @@ static int halt_now(enum action a) {
}
}
-static int halt_main(sd_bus *bus) {
+static int logind_schedule_shutdown(void) {
+
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ char date[FORMAT_TIMESTAMP_MAX];
+ const char *action;
+ sd_bus *bus;
int r;
- r = check_inhibitors(bus, arg_action);
+ (void) logind_set_wall_message();
+
+ r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
return r;
- if (geteuid() != 0) {
- /* Try logind if we are a normal user and no special
- * mode applies. Maybe PolicyKit allows us to shutdown
- * the machine. */
-
- if (arg_when <= 0 &&
- arg_force <= 0 &&
- (arg_action == ACTION_POWEROFF ||
- arg_action == ACTION_REBOOT)) {
- r = reboot_with_logind(bus, arg_action);
- if (r >= 0)
- return r;
- }
-
- log_error("Must be root.");
- return -EPERM;
+ switch (arg_action) {
+ case ACTION_HALT:
+ action = "halt";
+ break;
+ case ACTION_POWEROFF:
+ action = "poweroff";
+ break;
+ case ACTION_KEXEC:
+ action = "kexec";
+ break;
+ case ACTION_EXIT:
+ action = "exit";
+ break;
+ case ACTION_REBOOT:
+ default:
+ action = "reboot";
+ break;
}
- if (arg_when > 0) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
- _cleanup_free_ char *m = NULL;
- const char *action;
+ if (arg_dry)
+ action = strjoina("dry-", action);
- if (avoid_bus()) {
- log_error("Unable to perform operation without bus connection.");
- return -ENOSYS;
- }
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "ScheduleShutdown",
+ &error,
+ NULL,
+ "st",
+ action,
+ arg_when);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r));
- r = sd_bus_open_system(&b);
- if (r < 0)
- return log_error_errno(r, "Unable to open system bus: %m");
+ log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
+ return 0;
+#else
+ log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
+ return -ENOSYS;
+#endif
+}
- m = strv_join(arg_wall, " ");
- if (!m)
- return log_oom();
+static int halt_main(void) {
+ int r;
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
+ r = logind_check_inhibitors(arg_action);
+ if (r < 0)
+ return r;
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
+ if (arg_when > 0)
+ return logind_schedule_shutdown();
- switch (arg_action) {
- case ACTION_HALT:
- action = "halt";
- break;
- case ACTION_POWEROFF:
- action = "poweroff";
- break;
- case ACTION_KEXEC:
- action = "kexec";
- break;
- default:
- action = "reboot";
- break;
+ if (geteuid() != 0) {
+ if (arg_dry || arg_force > 0) {
+ log_error("Must be root.");
+ return -EPERM;
}
- if (arg_dry)
- action = strjoina("dry-", action);
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "ScheduleShutdown",
- &error,
- NULL,
- "st",
- action,
- arg_when);
- if (r < 0)
- log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s",
- bus_error_message(&error, r));
- else {
- char date[FORMAT_TIMESTAMP_MAX];
-
- log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.",
- format_timestamp(date, sizeof(date), arg_when));
- return 0;
+ /* Try logind if we are a normal user and no special
+ * mode applies. Maybe PolicyKit allows us to shutdown
+ * the machine. */
+ if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT)) {
+ r = logind_reboot(arg_action);
+ if (r >= 0)
+ return r;
+ if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS))
+ /* requested operation is not
+ * supported on the local system or
+ * already in progress */
+ return r;
+ /* on all other errors, try low-level operation */
}
}
if (!arg_dry && !arg_force)
- return start_with_fallback(bus);
+ return start_with_fallback();
+
+ assert(geteuid() == 0);
if (!arg_no_wtmp) {
if (sd_booted() > 0)
@@ -7465,9 +7653,7 @@ static int halt_main(sd_bus *bus) {
return 0;
r = halt_now(arg_action);
- log_error_errno(r, "Failed to reboot: %m");
-
- return r;
+ return log_error_errno(r, "Failed to reboot: %m");
}
static int runlevel_main(void) {
@@ -7486,8 +7672,37 @@ static int runlevel_main(void) {
return 0;
}
+static int logind_cancel_shutdown(void) {
+#ifdef HAVE_LOGIND
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_FULL, &bus);
+ if (r < 0)
+ return r;
+
+ (void) logind_set_wall_message();
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.login1",
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "CancelScheduledShutdown",
+ &error,
+ NULL, NULL);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r));
+
+ return 0;
+#else
+ log_error("Not compiled with logind support, cannot cancel scheduled shutdowns.");
+ return -ENOSYS;
+#endif
+}
+
int main(int argc, char*argv[]) {
- _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
@@ -7503,39 +7718,26 @@ int main(int argc, char*argv[]) {
if (r <= 0)
goto finish;
- /* /sbin/runlevel doesn't need to communicate via D-Bus, so
- * let's shortcut this */
- if (arg_action == ACTION_RUNLEVEL) {
- r = runlevel_main();
- goto finish;
- }
-
if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
log_info("Running in chroot, ignoring request.");
r = 0;
goto finish;
}
- if (!avoid_bus())
- r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus);
-
- if (bus)
- sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
-
/* systemctl_main() will print an error message for the bus
* connection, but only if it needs to */
switch (arg_action) {
case ACTION_SYSTEMCTL:
- r = systemctl_main(bus, argc, argv, r);
+ r = systemctl_main(argc, argv);
break;
case ACTION_HALT:
case ACTION_POWEROFF:
case ACTION_REBOOT:
case ACTION_KEXEC:
- r = halt_main(bus);
+ r = halt_main();
break;
case ACTION_RUNLEVEL2:
@@ -7545,69 +7747,22 @@ int main(int argc, char*argv[]) {
case ACTION_RESCUE:
case ACTION_EMERGENCY:
case ACTION_DEFAULT:
- r = start_with_fallback(bus);
+ r = start_with_fallback();
break;
case ACTION_RELOAD:
case ACTION_REEXEC:
- r = reload_with_fallback(bus);
+ r = reload_with_fallback();
break;
- case ACTION_CANCEL_SHUTDOWN: {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_flush_close_unref_ sd_bus *b = NULL;
- _cleanup_free_ char *m = NULL;
-
- if (avoid_bus()) {
- log_error("Unable to perform operation without bus connection.");
- return -ENOSYS;
- }
-
- r = sd_bus_open_system(&b);
- if (r < 0)
- return log_error_errno(r, "Unable to open system bus: %m");
-
- if (arg_wall) {
- m = strv_join(arg_wall, " ");
- if (!m) {
- r = log_oom();
- goto finish;
- }
- }
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "SetWallMessage",
- &error,
- NULL,
- "sb",
- m,
- !arg_no_wall);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to set wall message, ignoring: %s",
- bus_error_message(&error, r));
- sd_bus_error_free(&error);
- }
-
- r = sd_bus_call_method(
- b,
- "org.freedesktop.login1",
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- "CancelScheduledShutdown",
- &error,
- NULL, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s",
- bus_error_message(&error, r));
+ case ACTION_CANCEL_SHUTDOWN:
+ r = logind_cancel_shutdown();
break;
- }
case ACTION_RUNLEVEL:
+ r = runlevel_main();
+ break;
+
case _ACTION_INVALID:
default:
assert_not_reached("Unknown action");
@@ -7622,5 +7777,9 @@ finish:
strv_free(arg_states);
strv_free(arg_properties);
+ strv_free(arg_wall);
+
+ release_busses();
+
return r < 0 ? EXIT_FAILURE : r;
}
diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h
index 5439a1903b..43cf247cdf 100644
--- a/src/systemd/sd-bus.h
+++ b/src/systemd/sd-bus.h
@@ -158,6 +158,8 @@ sd_bus *sd_bus_ref(sd_bus *bus);
sd_bus *sd_bus_unref(sd_bus *bus);
sd_bus *sd_bus_flush_close_unref(sd_bus *bus);
+void sd_bus_default_flush_close(void);
+
int sd_bus_is_open(sd_bus *bus);
int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id);
@@ -418,7 +420,9 @@ int sd_bus_error_add_map(const sd_bus_error_map *map);
/* Label escaping */
int sd_bus_path_encode(const char *prefix, const char *external_id, char **ret_path);
+int sd_bus_path_encode_many(char **out, const char *path_template, ...);
int sd_bus_path_decode(const char *path, const char *prefix, char **ret_external_id);
+int sd_bus_path_decode_many(const char *path, const char *path_template, ...);
/* Tracking peers */
diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h
index 861dc8f1f4..214e77cab1 100644
--- a/src/systemd/sd-daemon.h
+++ b/src/systemd/sd-daemon.h
@@ -76,6 +76,8 @@ _SD_BEGIN_DECLARATIONS;
*/
int sd_listen_fds(int unset_environment);
+int sd_listen_fds_with_names(int unset_environment, char ***names);
+
/*
Helper call for identifying a passed file descriptor. Returns 1 if
the file descriptor is a FIFO in the file system stored under the
diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h
index 951662e56c..4291fb7ebc 100644
--- a/src/systemd/sd-dhcp-client.h
+++ b/src/systemd/sd-dhcp-client.h
@@ -29,11 +29,11 @@
#include "sd-dhcp-lease.h"
enum {
- DHCP_EVENT_STOP = 0,
- DHCP_EVENT_IP_ACQUIRE = 1,
- DHCP_EVENT_IP_CHANGE = 2,
- DHCP_EVENT_EXPIRED = 3,
- DHCP_EVENT_RENEW = 4,
+ SD_DHCP_CLIENT_EVENT_STOP = 0,
+ SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1,
+ SD_DHCP_CLIENT_EVENT_IP_CHANGE = 2,
+ SD_DHCP_CLIENT_EVENT_EXPIRED = 3,
+ SD_DHCP_CLIENT_EVENT_RENEW = 4,
};
typedef struct sd_dhcp_client sd_dhcp_client;
diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h
index e9663c0c71..90c35ef3f6 100644
--- a/src/systemd/sd-dhcp6-client.h
+++ b/src/systemd/sd-dhcp6-client.h
@@ -29,11 +29,11 @@
#include "sd-dhcp6-lease.h"
enum {
- DHCP6_EVENT_STOP = 0,
- DHCP6_EVENT_RESEND_EXPIRE = 10,
- DHCP6_EVENT_RETRANS_MAX = 11,
- DHCP6_EVENT_IP_ACQUIRE = 12,
- DHCP6_EVENT_INFORMATION_REQUEST = 13,
+ SD_DHCP6_CLIENT_EVENT_STOP = 0,
+ SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10,
+ SD_DHCP6_CLIENT_EVENT_RETRANS_MAX = 11,
+ SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE = 12,
+ SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13,
};
typedef struct sd_dhcp6_client sd_dhcp6_client;
diff --git a/src/systemd/sd-icmp6-nd.h b/src/systemd/sd-icmp6-nd.h
index 79b4074707..cb6c24a0cb 100644
--- a/src/systemd/sd-icmp6-nd.h
+++ b/src/systemd/sd-icmp6-nd.h
@@ -27,11 +27,11 @@
#include "sd-event.h"
enum {
- ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE = 0,
- ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1,
- ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER = 2,
- ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3,
- ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED = 4,
+ SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE = 0,
+ SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1,
+ SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER = 2,
+ SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3,
+ SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED = 4,
};
typedef struct sd_icmp6_nd sd_icmp6_nd;
@@ -64,9 +64,9 @@ int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr,
int sd_icmp6_nd_stop(sd_icmp6_nd *nd);
int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd);
-#define SD_ICMP6_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
+#define SD_ICMP6_ND_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x"
-#define SD_ICMP6_ADDRESS_FORMAT_VAL(address) \
+#define SD_ICMP6_ND_ADDRESS_FORMAT_VAL(address) \
be16toh((address).s6_addr16[0]), \
be16toh((address).s6_addr16[1]), \
be16toh((address).s6_addr16[2]), \
diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h
new file mode 100644
index 0000000000..adcb2c7b92
--- /dev/null
+++ b/src/systemd/sd-ipv4acd.h
@@ -0,0 +1,55 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosdipv4acdfoo
+#define foosdipv4acdfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Axis Communications AB. All rights reserved.
+ Copyright (C) 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+
+#include "sd-event.h"
+
+enum {
+ SD_IPV4ACD_EVENT_STOP = 0,
+ SD_IPV4ACD_EVENT_BIND = 1,
+ SD_IPV4ACD_EVENT_CONFLICT = 2,
+};
+
+typedef struct sd_ipv4acd sd_ipv4acd;
+typedef void (*sd_ipv4acd_cb_t)(sd_ipv4acd *ll, int event, void *userdata);
+
+int sd_ipv4acd_detach_event(sd_ipv4acd *ll);
+int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority);
+int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address);
+int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata);
+int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr);
+int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index);
+int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address);
+bool sd_ipv4acd_is_running(sd_ipv4acd *ll);
+int sd_ipv4acd_start(sd_ipv4acd *ll);
+int sd_ipv4acd_stop(sd_ipv4acd *ll);
+sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll);
+sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll);
+int sd_ipv4acd_new (sd_ipv4acd **ret);
+
+#endif
diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h
index d017158154..cc85140acd 100644
--- a/src/systemd/sd-ipv4ll.h
+++ b/src/systemd/sd-ipv4ll.h
@@ -29,9 +29,9 @@
#include "sd-event.h"
enum {
- IPV4LL_EVENT_STOP = 0,
- IPV4LL_EVENT_BIND = 1,
- IPV4LL_EVENT_CONFLICT = 2,
+ SD_IPV4LL_EVENT_STOP = 0,
+ SD_IPV4LL_EVENT_BIND = 1,
+ SD_IPV4LL_EVENT_CONFLICT = 2,
};
typedef struct sd_ipv4ll sd_ipv4ll;
@@ -43,7 +43,8 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
-int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint8_t seed[8]);
+int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);
+int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed);
bool sd_ipv4ll_is_running(sd_ipv4ll *ll);
int sd_ipv4ll_start(sd_ipv4ll *ll);
int sd_ipv4ll_stop(sd_ipv4ll *ll);
diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h
index 700146aba6..30d9dedf2c 100644
--- a/src/systemd/sd-lldp.h
+++ b/src/systemd/sd-lldp.h
@@ -24,21 +24,20 @@
#include "sd-event.h"
-typedef struct sd_lldp sd_lldp;
-
-typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata);
+enum {
+ SD_LLDP_EVENT_UPDATE_INFO = 0,
+};
enum {
- UPDATE_INFO = 10,
+ SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE,
+ SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE,
+ SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE,
};
-typedef enum LLDPPortStatus {
- LLDP_PORT_STATUS_NONE,
- LLDP_PORT_STATUS_ENABLED,
- LLDP_PORT_STATUS_DISABLED,
- _LLDP_PORT_STATUS_MAX,
- _LLDP_PORT_STATUS_INVALID = -1,
-} LLDPPortStatus;
+typedef struct sd_lldp sd_lldp;
+typedef struct sd_lldp_packet sd_lldp_packet;
+
+typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata);
int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret);
void sd_lldp_free(sd_lldp *lldp);
@@ -51,3 +50,25 @@ int sd_lldp_detach_event(sd_lldp *lldp);
int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata);
int sd_lldp_save(sd_lldp *lldp, const char *file);
+
+int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
+int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
+int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl);
+int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length);
+int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
+int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data);
+int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
+
+/* IEEE 802.1 organizationally specific TLVs */
+int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id);
+int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id);
+int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length);
+int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id);
+int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id);
+
+sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv);
+sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv);
+
+int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest);
+
+int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index cb462bf48f..8e1b06ee9a 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -104,6 +104,7 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump);
int sd_netlink_message_is_error(sd_netlink_message *m);
int sd_netlink_message_get_errno(sd_netlink_message *m);
int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type);
+int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags);
int sd_netlink_message_is_broadcast(sd_netlink_message *m);
/* rtnl */
@@ -136,6 +137,10 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char
int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope);
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol);
+int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope);
+int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos);
+int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table);
int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len);
int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len);
diff --git a/src/systemd/sd-pppoe.h b/src/systemd/sd-pppoe.h
index 318d2f033b..90878ffa27 100644
--- a/src/systemd/sd-pppoe.h
+++ b/src/systemd/sd-pppoe.h
@@ -30,8 +30,8 @@
#include "sparse-endian.h"
enum {
- PPPOE_EVENT_RUNNING = 0,
- PPPOE_EVENT_STOPPED = 1,
+ SD_PPPOE_EVENT_RUNNING = 0,
+ SD_PPPOE_EVENT_STOPPED = 1,
};
typedef struct sd_pppoe sd_pppoe;
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index aaa33354f4..ba09727080 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -19,26 +19,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <pwd.h>
+#include <getopt.h>
#include <grp.h>
-#include <shadow.h>
#include <gshadow.h>
-#include <getopt.h>
+#include <pwd.h>
+#include <shadow.h>
#include <utmp.h>
-#include "util.h"
-#include "hashmap.h"
-#include "specifier.h"
-#include "path-util.h"
-#include "build.h"
-#include "strv.h"
#include "conf-files.h"
#include "copy.h"
-#include "utf8.h"
#include "fileio-label.h"
-#include "uid-range.h"
-#include "selinux-util.h"
#include "formats-util.h"
+#include "hashmap.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "specifier.h"
+#include "strv.h"
+#include "uid-range.h"
+#include "utf8.h"
+#include "util.h"
+#include "smack-util.h"
typedef enum ItemType {
ADD_USER = 'u',
@@ -353,6 +353,19 @@ static int sync_rights(FILE *from, FILE *to) {
return 0;
}
+static int rename_and_apply_smack(const char *temp_path, const char *dest_path) {
+ int r = 0;
+ if (rename(temp_path, dest_path) < 0)
+ return -errno;
+
+#ifdef SMACK_RUN_LABEL
+ r = mac_smack_apply(dest_path, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL);
+ if (r < 0)
+ return r;
+#endif
+ return r;
+}
+
static int write_files(void) {
_cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL;
@@ -699,36 +712,32 @@ static int write_files(void) {
/* And make the new files count */
if (group_changed) {
if (group) {
- if (rename(group_tmp, group_path) < 0) {
- r = -errno;
+ r = rename_and_apply_smack(group_tmp, group_path);
+ if (r < 0)
goto finish;
- }
group_tmp = mfree(group_tmp);
}
if (gshadow) {
- if (rename(gshadow_tmp, gshadow_path) < 0) {
- r = -errno;
+ r = rename_and_apply_smack(gshadow_tmp, gshadow_path);
+ if (r < 0)
goto finish;
- }
gshadow_tmp = mfree(gshadow_tmp);
}
}
if (passwd) {
- if (rename(passwd_tmp, passwd_path) < 0) {
- r = -errno;
+ r = rename_and_apply_smack(passwd_tmp, passwd_path);
+ if (r < 0)
goto finish;
- }
passwd_tmp = mfree(passwd_tmp);
}
if (shadow) {
- if (rename(shadow_tmp, shadow_path) < 0) {
- r = -errno;
+ r = rename_and_apply_smack(shadow_tmp, shadow_path);
+ if (r < 0)
goto finish;
- }
shadow_tmp = mfree(shadow_tmp);
}
@@ -1767,9 +1776,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_ROOT:
free(arg_root);
diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c
index 45b119362c..964750076a 100644
--- a/src/sysv-generator/sysv-generator.c
+++ b/src/sysv-generator/sysv-generator.c
@@ -739,7 +739,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
if (hidden_file(de->d_name))
continue;
- if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
+ if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) {
log_warning_errno(errno, "stat() failed on %s/%s: %m", *path, de->d_name);
continue;
}
@@ -806,8 +806,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
if (!path)
return -ENOMEM;
- if (d)
- closedir(d);
+ safe_closedir(d);
d = opendir(path);
if (!d) {
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
index 87e1da1258..ad36ef19b0 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -50,6 +50,44 @@ static void test_one(const char *input, const char *output) {
assert_se(streq(q, p));
}
+static void test_next(const char *input, const char *new_tz, usec_t after, usec_t expect) {
+ CalendarSpec *c;
+ usec_t u;
+ char *old_tz;
+ char buf[FORMAT_TIMESTAMP_MAX];
+ int r;
+
+ old_tz = getenv("TZ");
+ if (old_tz)
+ old_tz = strdupa(old_tz);
+
+ if (new_tz)
+ assert_se(setenv("TZ", new_tz, 1) >= 0);
+ else
+ assert_se(unsetenv("TZ") >= 0);
+ tzset();
+
+ assert_se(calendar_spec_from_string(input, &c) >= 0);
+
+ printf("\"%s\"\n", input);
+
+ u = after;
+ r = calendar_spec_next_usec(c, after, &u);
+ printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u));
+ if (expect != (usec_t)-1)
+ assert_se(r >= 0 && u == expect);
+ else
+ assert(r == -ENOENT);
+
+ calendar_spec_free(c);
+
+ if (old_tz)
+ assert_se(setenv("TZ", old_tz, 1) >= 0);
+ else
+ assert_se(unsetenv("TZ") >= 0);
+ tzset();
+}
+
int main(int argc, char* argv[]) {
CalendarSpec *c;
@@ -82,6 +120,15 @@ int main(int argc, char* argv[]) {
test_one("semi-annually", "*-01,07-01 00:00:00");
test_one("annually", "*-01-01 00:00:00");
test_one("*:2/3", "*-*-* *:02/3:00");
+ test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC");
+
+ test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000);
+ test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000);
+ test_next("2016-03-27 03:17:00", "EET", 12345, -1);
+ test_next("2016-03-27 03:17:00 UTC", NULL, 12345, 1459048620000000);
+ test_next("2016-03-27 03:17:00 UTC", "", 12345, 1459048620000000);
+ test_next("2016-03-27 03:17:00 UTC", "CET", 12345, 1459048620000000);
+ test_next("2016-03-27 03:17:00 UTC", "EET", 12345, 1459048620000000);
assert_se(calendar_spec_from_string("test", &c) < 0);
assert_se(calendar_spec_from_string("", &c) < 0);
diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c
index 7e0ac754d1..45fb554445 100644
--- a/src/test/test-daemon.c
+++ b/src/test/test-daemon.c
@@ -21,9 +21,22 @@
#include <unistd.h>
-#include "systemd/sd-daemon.h"
+#include "sd-daemon.h"
+
+#include "strv.h"
int main(int argc, char*argv[]) {
+ _cleanup_strv_free_ char **l = NULL;
+ int n, i;
+
+ n = sd_listen_fds_with_names(false, &l);
+ if (n < 0) {
+ log_error_errno(n, "Failed to get listening fds: %m");
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; i < n; i++)
+ log_info("fd=%i name=%s\n", SD_LISTEN_FDS_START + i, l[i]);
sd_notify(0,
"STATUS=Starting up");
@@ -49,5 +62,5 @@ int main(int argc, char*argv[]) {
"STOPPING=1");
sleep(5);
- return 0;
+ return EXIT_SUCCESS;
}
diff --git a/src/test/test-date.c b/src/test/test-date.c
index 00b569080c..bd1b2781df 100644
--- a/src/test/test-date.c
+++ b/src/test/test-date.c
@@ -23,12 +23,12 @@
#include "util.h"
-static void test_one(const char *p) {
+static void test_should_pass(const char *p) {
usec_t t, q;
char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX];
assert_se(parse_timestamp(p, &t) >= 0);
- format_timestamp(buf, sizeof(buf), t);
+ format_timestamp_us(buf, sizeof(buf), t);
log_info("%s", buf);
/* Chop off timezone */
@@ -42,23 +42,50 @@ static void test_one(const char *p) {
assert_se(parse_timestamp(buf, &q) >= 0);
}
+static void test_should_fail(const char *p) {
+ usec_t t;
+
+ assert_se(parse_timestamp(p, &t) < 0);
+}
+
+static void test_one(const char *p) {
+ _cleanup_free_ char *with_utc;
+
+ log_info("Test: %s", p);
+ with_utc = strjoin(p, " UTC", NULL);
+ test_should_pass(p);
+ test_should_pass(with_utc);
+}
+
+static void test_one_noutc(const char *p) {
+ _cleanup_free_ char *with_utc;
+
+ log_info("Test: %s", p);
+ with_utc = strjoin(p, " UTC", NULL);
+ test_should_pass(p);
+ test_should_fail(with_utc);
+}
+
int main(int argc, char *argv[]) {
test_one("17:41");
test_one("18:42:44");
+ test_one("18:42:44.0");
+ test_one("18:42:44.999999999999");
test_one("12-10-02 12:13:14");
test_one("12-10-2 12:13:14");
test_one("12-10-03 12:13");
test_one("2012-12-30 18:42");
test_one("2012-10-02");
test_one("Tue 2012-10-02");
- test_one("now");
+ test_one_noutc("now");
test_one("yesterday");
test_one("today");
test_one("tomorrow");
- test_one("+2d");
- test_one("+2y 4d");
- test_one("5months ago");
- test_one("@1395716396");
+ test_one_noutc("+2d");
+ test_one_noutc("+2y 4d");
+ test_one_noutc("5months ago");
+ test_one_noutc("@1395716396");
+ test_one_noutc("today UTC");
return 0;
}
diff --git a/src/test/test-env-replace.c b/src/test/test-env-replace.c
index 2e28c0c49b..110223f3b8 100644
--- a/src/test/test-env-replace.c
+++ b/src/test/test-env-replace.c
@@ -118,6 +118,8 @@ static void test_replace_env_arg(void) {
"$FOO$FOO",
"${FOO}${BAR}",
"${FOO",
+ "FOO$$${FOO}",
+ "$$FOO${FOO}",
NULL
};
_cleanup_strv_free_ char **r = NULL;
@@ -133,7 +135,9 @@ static void test_replace_env_arg(void) {
assert_se(streq(r[6], "BAR"));
assert_se(streq(r[7], "BAR BARwaldo"));
assert_se(streq(r[8], "${FOO"));
- assert_se(strv_length(r) == 9);
+ assert_se(streq(r[9], "FOO$BAR BAR"));
+ assert_se(streq(r[10], "$FOOBAR BAR"));
+ assert_se(strv_length(r) == 11);
}
static void test_env_clean(void) {
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 0f4172e722..fa6336f1fb 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -77,10 +77,14 @@ static void test_exec_workingdirectory(Manager *m) {
}
static void test_exec_personality(Manager *m) {
- test(m, "exec-personality-x86.service", 0, CLD_EXITED);
-
#if defined(__x86_64__)
test(m, "exec-personality-x86-64.service", 0, CLD_EXITED);
+
+#elif defined(__s390__)
+ test(m, "exec-personality-s390.service", 0, CLD_EXITED);
+
+#else
+ test(m, "exec-personality-x86.service", 0, CLD_EXITED);
#endif
}
@@ -137,6 +141,12 @@ static void test_exec_umask(Manager *m) {
test(m, "exec-umask-0177.service", 0, CLD_EXITED);
}
+static void test_exec_runtimedirectory(Manager *m) {
+ test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
+ test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
+ test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+}
+
int main(int argc, char *argv[]) {
test_function_t tests[] = {
test_exec_workingdirectory,
@@ -150,6 +160,7 @@ int main(int argc, char *argv[]) {
test_exec_group,
test_exec_environment,
test_exec_umask,
+ test_exec_runtimedirectory,
NULL,
};
test_function_t *test = NULL;
@@ -165,6 +176,7 @@ int main(int argc, char *argv[]) {
return EXIT_TEST_SKIP;
}
+ assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0);
assert_se(set_unit_path(TEST_DIR) >= 0);
r = manager_new(MANAGER_USER, true, &m);
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index be3a87958f..ad547822e7 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -241,18 +241,18 @@ static void test_status_field(void) {
unsigned long long total = 0, buffers = 0;
int r;
- assert_se(get_status_field("/proc/self/status", "\nThreads:", &t) == 0);
+ assert_se(get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t) == 0);
puts(t);
assert_se(streq(t, "1"));
- r = get_status_field("/proc/meminfo", "MemTotal:", &p);
+ r = get_proc_field("/proc/meminfo", "MemTotal", WHITESPACE, &p);
if (r != -ENOENT) {
assert_se(r == 0);
puts(p);
assert_se(safe_atollu(p, &total) == 0);
}
- r = get_status_field("/proc/meminfo", "\nBuffers:", &s);
+ r = get_proc_field("/proc/meminfo", "Buffers", WHITESPACE, &s);
if (r != -ENOENT) {
assert_se(r == 0);
puts(s);
@@ -263,7 +263,7 @@ static void test_status_field(void) {
assert_se(buffers < total);
/* Seccomp should be a good test for field full of zeros. */
- r = get_status_field("/proc/meminfo", "\nSeccomp:", &z);
+ r = get_proc_field("/proc/meminfo", "Seccomp", WHITESPACE, &z);
if (r != -ENOENT) {
assert_se(r == 0);
puts(z);
diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c
index 057b6c1dc1..c691f577c6 100644
--- a/src/test/test-hashmap-plain.c
+++ b/src/test/test-hashmap-plain.c
@@ -692,8 +692,8 @@ static void test_hashmap_get2(void) {
hashmap_free_free_free(m);
}
-static unsigned long crippled_hashmap_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) {
- return trivial_hash_func(p, hash_key) & 0xff;
+static void crippled_hashmap_func(const void *p, struct siphash *state) {
+ return trivial_hash_func(INT_TO_PTR(PTR_TO_INT(p) & 0xff), state);
}
static const struct hash_ops crippled_hashmap_ops = {
@@ -710,7 +710,7 @@ static void test_hashmap_many(void) {
unsigned n_entries;
} tests[] = {
{ .ops = NULL, .n_entries = 1 << 20 },
- { .ops = &crippled_hashmap_ops, .n_entries = 1 << 11 },
+ { .ops = &crippled_hashmap_ops, .n_entries = 1 << 14 },
};
diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c
index dfedc9b8dc..1e2e42cbca 100644
--- a/src/test/test-prioq.c
+++ b/src/test/test-prioq.c
@@ -89,13 +89,10 @@ static int test_compare(const void *a, const void *b) {
return 0;
}
-static unsigned long test_hash(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) {
+static void test_hash(const void *a, struct siphash *state) {
const struct test *x = a;
- uint64_t u;
- siphash24((uint8_t*) &u, &x->value, sizeof(x->value), hash_key);
-
- return (unsigned long) u;
+ siphash24_compress(&x->value, sizeof(x->value), state);
}
static const struct hash_ops test_hash_ops = {
diff --git a/src/test/test-pty.c b/src/test/test-pty.c
deleted file mode 100644
index fbab3d4ebe..0000000000
--- a/src/test/test-pty.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <locale.h>
-#include <string.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "pty.h"
-#include "util.h"
-#include "signal-util.h"
-
-static const char sndmsg[] = "message\n";
-static const char rcvmsg[] = "message\r\n";
-static char rcvbuf[128];
-static size_t rcvsiz = 0;
-static sd_event *event;
-
-static void run_child(Pty *pty) {
- ssize_t r, l;
- char buf[512];
-
- r = read(0, buf, sizeof(buf));
- assert_se((size_t)r == strlen(sndmsg));
- assert_se(!strncmp(buf, sndmsg, r));
-
- l = write(1, buf, r);
- assert_se(l == r);
-}
-
-static int pty_fn(Pty *pty, void *userdata, unsigned int ev, const void *ptr, size_t size) {
- switch (ev) {
- case PTY_DATA:
- assert_se(rcvsiz < strlen(rcvmsg) * 2);
- assert_se(rcvsiz + size < sizeof(rcvbuf));
-
- memcpy(&rcvbuf[rcvsiz], ptr, size);
- rcvsiz += size;
-
- if (rcvsiz >= strlen(rcvmsg) * 2) {
- assert_se(rcvsiz == strlen(rcvmsg) * 2);
- assert_se(!memcmp(rcvbuf, rcvmsg, strlen(rcvmsg)));
- assert_se(!memcmp(&rcvbuf[strlen(rcvmsg)], rcvmsg, strlen(rcvmsg)));
- }
-
- break;
- case PTY_HUP:
- /* This is guaranteed to appear _after_ the input queues are
- * drained! */
- assert_se(rcvsiz == strlen(rcvmsg) * 2);
- break;
- case PTY_CHILD:
- /* this may appear at any time */
- break;
- default:
- assert_se(0);
- break;
- }
-
- /* if we got HUP _and_ CHILD, exit */
- if (pty_get_fd(pty) < 0 && pty_get_child(pty) < 0)
- sd_event_exit(event, 0);
-
- return 0;
-}
-
-static void run_parent(Pty *pty) {
- int r;
-
- /* write message to pty, ECHO mode guarantees that we get it back
- * twice: once via ECHO, once from the run_child() fn */
- assert_se(pty_write(pty, sndmsg, strlen(sndmsg)) >= 0);
-
- r = sd_event_loop(event);
- assert_se(r >= 0);
-}
-
-static void test_pty(void) {
- pid_t pid;
- Pty *pty = NULL;
-
- rcvsiz = 0;
- zero(rcvbuf);
-
- assert_se(sd_event_default(&event) >= 0);
-
- pid = pty_fork(&pty, event, pty_fn, NULL, 80, 25);
- assert_se(pid >= 0);
-
- if (pid == 0) {
- /* child */
- run_child(pty);
- exit(0);
- }
-
- /* parent */
- run_parent(pty);
-
- /* Make sure the PTY recycled the child; yeah, this is racy if the
- * PID was already reused; but that seems fine for a test. */
- assert_se(waitpid(pid, NULL, WNOHANG) < 0 && errno == ECHILD);
-
- pty_unref(pty);
- sd_event_unref(event);
-}
-
-int main(int argc, char *argv[]) {
- unsigned int i;
-
- log_parse_environment();
- log_open();
-
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
-
- /* Oh, there're ugly races in the TTY layer regarding HUP vs IN. Turns
- * out they appear only 10% of the time. I fixed all of them and
- * don't see them, anymore. But let's be safe and run this 1000 times
- * so we catch any new ones, in case they appear again. */
- for (i = 0; i < 1000; ++i)
- test_pty();
-
- return 0;
-}
diff --git a/src/test/test-ring.c b/src/test/test-ring.c
deleted file mode 100644
index cb8a5d4e9e..0000000000
--- a/src/test/test-ring.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2014 David Herrmann <dh.herrmann@gmail.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-
-#include "def.h"
-#include "ring.h"
-
-static void test_ring(void) {
- static const char buf[8192];
- Ring r;
- size_t l;
- struct iovec vec[2];
- int s;
-
- zero(r);
-
- l = ring_peek(&r, vec);
- assert_se(l == 0);
-
- s = ring_push(&r, buf, 2048);
- assert_se(!s);
- assert_se(ring_get_size(&r) == 2048);
-
- l = ring_peek(&r, vec);
- assert_se(l == 1);
- assert_se(vec[0].iov_len == 2048);
- assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len));
- assert_se(ring_get_size(&r) == 2048);
-
- ring_pull(&r, 2048);
- assert_se(ring_get_size(&r) == 0);
-
- l = ring_peek(&r, vec);
- assert_se(l == 0);
- assert_se(ring_get_size(&r) == 0);
-
- s = ring_push(&r, buf, 2048);
- assert_se(!s);
- assert_se(ring_get_size(&r) == 2048);
-
- l = ring_peek(&r, vec);
- assert_se(l == 1);
- assert_se(vec[0].iov_len == 2048);
- assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len));
- assert_se(ring_get_size(&r) == 2048);
-
- s = ring_push(&r, buf, 1);
- assert_se(!s);
- assert_se(ring_get_size(&r) == 2049);
-
- l = ring_peek(&r, vec);
- assert_se(l == 2);
- assert_se(vec[0].iov_len == 2048);
- assert_se(vec[1].iov_len == 1);
- assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len));
- assert_se(!memcmp(vec[1].iov_base, buf, vec[1].iov_len));
- assert_se(ring_get_size(&r) == 2049);
-
- ring_pull(&r, 2048);
- assert_se(ring_get_size(&r) == 1);
-
- l = ring_peek(&r, vec);
- assert_se(l == 1);
- assert_se(vec[0].iov_len == 1);
- assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len));
- assert_se(ring_get_size(&r) == 1);
-
- ring_pull(&r, 1);
- assert_se(ring_get_size(&r) == 0);
-
- s = ring_push(&r, buf, 2048);
- assert_se(!s);
- assert_se(ring_get_size(&r) == 2048);
-
- s = ring_push(&r, buf, 2049);
- assert_se(!s);
- assert_se(ring_get_size(&r) == 4097);
-
- l = ring_peek(&r, vec);
- assert_se(l == 1);
- assert_se(vec[0].iov_len == 4097);
- assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len));
- assert_se(ring_get_size(&r) == 4097);
-
- ring_pull(&r, 1);
- assert_se(ring_get_size(&r) == 4096);
-
- s = ring_push(&r, buf, 4096);
- assert_se(!s);
- assert_se(ring_get_size(&r) == 8192);
-
- l = ring_peek(&r, vec);
- assert_se(l == 2);
- assert_se(vec[0].iov_len == 8191);
- assert_se(vec[1].iov_len == 1);
- assert_se(!memcmp(vec[0].iov_base, buf, vec[0].iov_len));
- assert_se(!memcmp(vec[1].iov_base, buf, vec[1].iov_len));
- assert_se(ring_get_size(&r) == 8192);
-
- ring_clear(&r);
- assert_se(ring_get_size(&r) == 0);
-}
-
-int main(int argc, char *argv[]) {
- log_parse_environment();
- log_open();
-
- test_ring();
-
- return 0;
-}
diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c
new file mode 100644
index 0000000000..2402da6a6f
--- /dev/null
+++ b/src/test/test-siphash24.c
@@ -0,0 +1,70 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "util.h"
+#include "siphash24.h"
+
+#define ITERATIONS 10000000ULL
+
+/* see https://131002.net/siphash/siphash.pdf, Appendix A */
+int main(int argc, char *argv[]) {
+ struct siphash state = {};
+ const uint8_t in[15] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e };
+ const uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+ uint64_t out = 0;
+ unsigned i, j;
+
+ siphash24((uint8_t *)&out, in, sizeof(in), key);
+ assert_se(out == htole64(0xa129ca6149be45e5));
+
+ /* verify the internal state as given in the above paper */
+ siphash24_init(&state, key);
+ assert_se(state.v0 == 0x7469686173716475);
+ assert_se(state.v1 == 0x6b617f6d656e6665);
+ assert_se(state.v2 == 0x6b7f62616d677361);
+ assert_se(state.v3 == 0x7b6b696e727e6c7b);
+ siphash24_compress(in, sizeof(in), &state);
+ assert_se(state.v0 == 0x4a017198de0a59e0);
+ assert_se(state.v1 == 0x0d52f6f62a4f59a4);
+ assert_se(state.v2 == 0x634cb3577b01fd3d);
+ assert_se(state.v3 == 0xa5224d6f55c7d9c8);
+ siphash24_finalize((uint8_t*)&out, &state);
+ assert_se(out == htole64(0xa129ca6149be45e5));
+ assert_se(state.v0 == 0xf6bcd53893fecff1);
+ assert_se(state.v1 == 0x54b9964c7ea0d937);
+ assert_se(state.v2 == 0x1b38329c099bb55a);
+ assert_se(state.v3 == 0x1814bb89ad7be679);
+
+ /* verify that decomposing the input in three chunks gives the
+ same result */
+ for (i = 0; i < sizeof(in); i++) {
+ for (j = i; j < sizeof(in); j++) {
+ siphash24_init(&state, key);
+ siphash24_compress(in, i, &state);
+ siphash24_compress(&in[i], j - i, &state);
+ siphash24_compress(&in[j], sizeof(in) - j, &state);
+ siphash24_finalize((uint8_t*)&out, &state);
+ assert_se(out == htole64(0xa129ca6149be45e5));
+ }
+ }
+}
diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c
index 358454842a..6cec8768b1 100644
--- a/src/test/test-strip-tab-ansi.c
+++ b/src/test/test-strip-tab-ansi.c
@@ -33,13 +33,13 @@ int main(int argc, char *argv[]) {
assert_se(streq(p, " Foobar bar waldo "));
free(p);
- assert_se(p = strdup(ANSI_HIGHLIGHT_ON "Hello" ANSI_HIGHLIGHT_OFF ANSI_HIGHLIGHT_RED_ON " world!" ANSI_HIGHLIGHT_OFF));
+ assert_se(p = strdup(ANSI_HIGHLIGHT "Hello" ANSI_NORMAL ANSI_HIGHLIGHT_RED " world!" ANSI_NORMAL));
assert_se(strip_tab_ansi(&p, NULL));
fprintf(stdout, "<%s>\n", p);
assert_se(streq(p, "Hello world!"));
free(p);
- assert_se(p = strdup("\x1B[\x1B[\t\x1B[" ANSI_HIGHLIGHT_ON "\x1B[" "Hello" ANSI_HIGHLIGHT_OFF ANSI_HIGHLIGHT_RED_ON " world!" ANSI_HIGHLIGHT_OFF));
+ assert_se(p = strdup("\x1B[\x1B[\t\x1B[" ANSI_HIGHLIGHT "\x1B[" "Hello" ANSI_NORMAL ANSI_HIGHLIGHT_RED " world!" ANSI_NORMAL));
assert_se(strip_tab_ansi(&p, NULL));
assert_se(streq(p, "\x1B[\x1B[ \x1B[\x1B[Hello world!"));
free(p);
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index bff43950a9..623c926521 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -155,7 +155,7 @@ static void test_strv_join(void) {
static void test_strv_quote_unquote(const char* const *split, const char *quoted) {
_cleanup_free_ char *p;
- _cleanup_strv_free_ char **s;
+ _cleanup_strv_free_ char **s = NULL;
char **t;
int r;
@@ -166,7 +166,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted
assert_se(streq(p, quoted));
r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES);
- assert_se(r == 0);
+ assert_se(r == (int) strv_length(s));
assert_se(s);
STRV_FOREACH(t, s) {
assert_se(*t);
@@ -183,7 +183,7 @@ static void test_strv_unquote(const char *quoted, char **list) {
int r;
r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES);
- assert_se(r == 0);
+ assert_se(r == (int) strv_length(list));
assert_se(s);
j = strv_join(s, " | ");
assert_se(j);
@@ -225,7 +225,7 @@ static void test_strv_split_extract(void) {
int r;
r = strv_split_extract(&l, str, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
- assert_se(r == 0);
+ assert_se(r == (int) strv_length(l));
assert_se(streq_ptr(l[0], ""));
assert_se(streq_ptr(l[1], "foo:bar"));
assert_se(streq_ptr(l[2], ""));
@@ -341,11 +341,11 @@ static void test_strv_extend_strv(void) {
_cleanup_strv_free_ char **a = NULL, **b = NULL;
a = strv_new("abc", "def", "ghi", NULL);
- b = strv_new("jkl", "mno", "pqr", NULL);
+ b = strv_new("jkl", "mno", "abc", "pqr", NULL);
assert_se(a);
assert_se(b);
- assert_se(strv_extend_strv(&a, b) >= 0);
+ assert_se(strv_extend_strv(&a, b, true) == 3);
assert_se(streq(a[0], "abc"));
assert_se(streq(a[1], "def"));
@@ -569,6 +569,77 @@ static void test_strv_shell_escape(void) {
assert_se(streq_ptr(v[3], NULL));
}
+static void test_strv_skip_one(char **a, size_t n, char **b) {
+ a = strv_skip(a, n);
+ assert_se(strv_equal(a, b));
+}
+
+static void test_strv_skip(void) {
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 0, STRV_MAKE("foo", "bar", "baz"));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 1, STRV_MAKE("bar", "baz"));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 2, STRV_MAKE("baz"));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 3, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 4, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 55, STRV_MAKE(NULL));
+
+ test_strv_skip_one(STRV_MAKE("quux"), 0, STRV_MAKE("quux"));
+ test_strv_skip_one(STRV_MAKE("quux"), 1, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE("quux"), 55, STRV_MAKE(NULL));
+
+ test_strv_skip_one(STRV_MAKE(NULL), 0, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE(NULL), 1, STRV_MAKE(NULL));
+ test_strv_skip_one(STRV_MAKE(NULL), 55, STRV_MAKE(NULL));
+}
+
+static void test_strv_extend_n(void) {
+ _cleanup_strv_free_ char **v = NULL;
+
+ v = strv_new("foo", "bar", NULL);
+ assert_se(v);
+
+ assert_se(strv_extend_n(&v, "waldo", 3) >= 0);
+ assert_se(strv_extend_n(&v, "piep", 2) >= 0);
+
+ assert_se(streq(v[0], "foo"));
+ assert_se(streq(v[1], "bar"));
+ assert_se(streq(v[2], "waldo"));
+ assert_se(streq(v[3], "waldo"));
+ assert_se(streq(v[4], "waldo"));
+ assert_se(streq(v[5], "piep"));
+ assert_se(streq(v[6], "piep"));
+ assert_se(v[7] == NULL);
+
+ v = strv_free(v);
+
+ assert_se(strv_extend_n(&v, "foo", 1) >= 0);
+ assert_se(strv_extend_n(&v, "bar", 0) >= 0);
+
+ assert_se(streq(v[0], "foo"));
+ assert_se(v[1] == NULL);
+}
+
+static void test_strv_make_nulstr_one(char **l) {
+ _cleanup_free_ char *b = NULL, *c = NULL;
+ _cleanup_strv_free_ char **q = NULL;
+ size_t n, m;
+
+ assert_se(strv_make_nulstr(l, &b, &n) >= 0);
+ assert_se(q = strv_parse_nulstr(b, n));
+ assert_se(strv_equal(l, q));
+
+ assert_se(strv_make_nulstr(q, &c, &m) >= 0);
+ assert_se(m == n);
+ assert_se(memcmp(b, c, m) == 0);
+}
+
+static void test_strv_make_nulstr(void) {
+ test_strv_make_nulstr_one(NULL);
+ test_strv_make_nulstr_one(STRV_MAKE(NULL));
+ test_strv_make_nulstr_one(STRV_MAKE("foo"));
+ test_strv_make_nulstr_one(STRV_MAKE("foo", "bar"));
+ test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux"));
+}
+
int main(int argc, char *argv[]) {
test_specifier_printf();
test_strv_foreach();
@@ -627,6 +698,9 @@ int main(int argc, char *argv[]) {
test_strv_is_uniq();
test_strv_reverse();
test_strv_shell_escape();
+ test_strv_skip();
+ test_strv_extend_n();
+ test_strv_make_nulstr();
return 0;
}
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 7935442dbb..503e840803 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -20,25 +20,28 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <string.h>
-#include <unistd.h>
+#include <errno.h>
#include <fcntl.h>
#include <locale.h>
-#include <errno.h>
-#include <signal.h>
#include <math.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/xattr.h>
+#include <unistd.h>
-#include "util.h"
-#include "mkdir.h"
-#include "rm-rf.h"
-#include "strv.h"
+#include "conf-parser.h"
+#include "cpu-set-util.h"
#include "def.h"
#include "fileio.h"
-#include "conf-parser.h"
-#include "virt.h"
+#include "mkdir.h"
#include "process-util.h"
+#include "rm-rf.h"
#include "signal-util.h"
+#include "strv.h"
+#include "util.h"
+#include "virt.h"
static void test_streq_ptr(void) {
assert_se(streq_ptr(NULL, NULL));
@@ -960,6 +963,64 @@ static void test_parse_size(void) {
assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE);
}
+static void test_parse_cpu_set(void) {
+ cpu_set_t *c = NULL;
+ int ncpus;
+ int cpu;
+
+ /* Simple range (from CPUAffinity example) */
+ ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2);
+ c = mfree(c);
+
+ /* A more interesting range */
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ for (cpu = 0; cpu < 4; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ for (cpu = 8; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Quoted strings */
+ ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4);
+ for (cpu = 8; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Use commas as separators */
+ ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus < 0);
+ assert_se(!c);
+
+ /* Ranges */
+ ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus < 0);
+ assert_se(!c);
+
+ /* Garbage */
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus < 0);
+ assert_se(!c);
+
+ /* Empty string */
+ c = NULL;
+ ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus == 0); /* empty string returns 0 */
+ assert_se(!c);
+
+ /* Runnaway quoted string */
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus < 0);
+ assert_se(!c);
+}
+
static void test_config_parse_iec_uint64(void) {
uint64_t offset = 0;
assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0);
@@ -2204,6 +2265,38 @@ static void test_strcmp_ptr(void) {
assert_se(strcmp_ptr("", "") == 0);
}
+static void test_fgetxattrat_fake(void) {
+ char t[] = "/var/tmp/xattrtestXXXXXX";
+ _cleanup_close_ int fd = -1;
+ const char *x;
+ char v[3] = {};
+ int r;
+
+ assert_se(mkdtemp(t));
+ x = strjoina(t, "/test");
+ assert_se(touch(x) >= 0);
+
+ r = setxattr(x, "user.foo", "bar", 3, 0);
+ if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */
+ goto cleanup;
+ assert_se(r >= 0);
+
+ fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY);
+ assert_se(fd >= 0);
+
+ assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0);
+ assert_se(memcmp(v, "bar", 3) == 0);
+
+ safe_close(fd);
+ fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY);
+ assert_se(fd >= 0);
+ assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA);
+
+cleanup:
+ assert_se(unlink(x) >= 0);
+ assert_se(rmdir(t) >= 0);
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -2250,6 +2343,7 @@ int main(int argc, char *argv[]) {
test_u64log2();
test_protect_errno();
test_parse_size();
+ test_parse_cpu_set();
test_config_parse_iec_uint64();
test_strextend();
test_strrep();
@@ -2293,6 +2387,7 @@ int main(int argc, char *argv[]) {
test_parse_mode();
test_tempfn();
test_strcmp_ptr();
+ test_fgetxattrat_fake();
return 0;
}
diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c
index 1c3f03c803..68fbe3f5b8 100644
--- a/src/timedate/timedatectl.c
+++ b/src/timedate/timedatectl.c
@@ -20,20 +20,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
-#include <stdbool.h>
#include <getopt.h>
#include <locale.h>
+#include <stdbool.h>
+#include <stdlib.h>
#include "sd-bus.h"
-#include "bus-util.h"
+
#include "bus-error.h"
-#include "util.h"
+#include "bus-util.h"
+#include "pager.h"
#include "spawn-polkit-agent.h"
-#include "build.h"
#include "strv.h"
-#include "pager.h"
#include "terminal-util.h"
+#include "util.h"
static bool arg_no_pager = false;
static bool arg_ask_password = true;
@@ -153,13 +153,13 @@ static void print_status_info(const StatusInfo *i) {
yes_no(i->rtc_local));
if (i->rtc_local)
- fputs("\n" ANSI_HIGHLIGHT_ON
+ fputs("\n" ANSI_HIGHLIGHT
"Warning: The system is configured to read the RTC time in the local time zone.\n"
" This mode can not be fully supported. It will create various problems\n"
" with time zone changes and daylight saving time adjustments. The RTC\n"
" time is never updated, it relies on external facilities to maintain it.\n"
" If at all possible, use RTC in UTC by calling\n"
- " 'timedatectl set-local-rtc 0'" ANSI_HIGHLIGHT_OFF ".\n", stdout);
+ " 'timedatectl set-local-rtc 0'." ANSI_NORMAL "\n", stdout);
}
static int show_status(sd_bus *bus, char **args, unsigned n) {
@@ -374,9 +374,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
@@ -502,7 +500,7 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = bus_open_transport(arg_transport, arg_host, false, &bus);
+ r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c
index df4d89a620..28ad378a93 100644
--- a/src/timesync/timesyncd-conf.c
+++ b/src/timesync/timesyncd-conf.c
@@ -85,7 +85,7 @@ int config_parse_servers(
else {
r = manager_parse_server_string(m, ltype, rvalue);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse NTP server string '%s'. Ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NTP server string '%s'. Ignoring.", rvalue);
return 0;
}
}
diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c
index 7b4178c993..3cb7d435cd 100644
--- a/src/timesync/timesyncd.c
+++ b/src/timesync/timesyncd.c
@@ -131,7 +131,7 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_warning_errno(r, "Failed to parse configuration file: %m");
- log_debug("systemd-timesyncd running as pid %lu", (unsigned long) getpid());
+ log_debug("systemd-timesyncd running as pid " PID_FMT, getpid());
sd_notify(false,
"READY=1\n"
"STATUS=Daemon is running");
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 8f29256c6d..d219764bc6 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -20,43 +20,42 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <fcntl.h>
+#include <dirent.h>
#include <errno.h>
-#include <string.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <getopt.h>
+#include <glob.h>
#include <limits.h>
-#include <dirent.h>
+#include <linux/fs.h>
+#include <stdbool.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stddef.h>
-#include <getopt.h>
-#include <stdbool.h>
-#include <time.h>
-#include <glob.h>
-#include <fnmatch.h>
+#include <string.h>
#include <sys/stat.h>
#include <sys/xattr.h>
-#include <linux/fs.h>
+#include <time.h>
+#include <unistd.h>
+#include "acl-util.h"
+#include "btrfs-util.h"
+#include "capability.h"
+#include "conf-files.h"
+#include "copy.h"
+#include "formats-util.h"
+#include "label.h"
#include "log.h"
-#include "util.h"
#include "macro.h"
#include "missing.h"
#include "mkdir.h"
#include "path-util.h"
-#include "strv.h"
-#include "label.h"
-#include "set.h"
-#include "conf-files.h"
-#include "capability.h"
-#include "specifier.h"
-#include "build.h"
-#include "copy.h"
#include "rm-rf.h"
#include "selinux-util.h"
-#include "btrfs-util.h"
-#include "acl-util.h"
-#include "formats-util.h"
+#include "set.h"
+#include "specifier.h"
+#include "strv.h"
+#include "util.h"
/* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
* them in the file system. This is intended to be used to create
@@ -2090,9 +2089,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_CREATE:
arg_create = true;
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index 82cbf95f1e..53986babae 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -19,32 +19,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdbool.h>
#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stddef.h>
#include <string.h>
+#include <sys/inotify.h>
+#include <sys/signalfd.h>
#include <sys/socket.h>
#include <sys/un.h>
-#include <stddef.h>
-#include <poll.h>
-#include <sys/inotify.h>
#include <unistd.h>
-#include <getopt.h>
-#include <sys/signalfd.h>
-#include <fcntl.h>
-#include "util.h"
+#include "ask-password-api.h"
+#include "conf-parser.h"
+#include "def.h"
#include "mkdir.h"
#include "path-util.h"
-#include "conf-parser.h"
-#include "utmp-wtmp.h"
+#include "process-util.h"
+#include "signal-util.h"
#include "socket-util.h"
-#include "ask-password-api.h"
#include "strv.h"
-#include "build.h"
-#include "def.h"
-#include "process-util.h"
#include "terminal-util.h"
-#include "signal-util.h"
+#include "util.h"
+#include "utmp-wtmp.h"
static enum {
ACTION_LIST,
@@ -59,9 +58,9 @@ static bool arg_console = false;
static int ask_password_plymouth(
const char *message,
usec_t until,
+ AskPasswordFlags flags,
const char *flag_file,
- bool accept_cached,
- char ***_passphrases) {
+ char ***ret) {
_cleanup_close_ int fd = -1, notify = -1;
union sockaddr_union sa = PLYMOUTH_SOCKET;
@@ -76,7 +75,7 @@ static int ask_password_plymouth(
POLL_INOTIFY
};
- assert(_passphrases);
+ assert(ret);
if (flag_file) {
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
@@ -94,17 +93,15 @@ static int ask_password_plymouth(
r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
if (r < 0)
- return log_error_errno(errno, "Failed to connect to Plymouth: %m");
+ return -errno;
- if (accept_cached) {
+ if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
packet = strdup("c");
n = 1;
- } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1),
- message, &n) < 0)
+ } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0)
packet = NULL;
-
if (!packet)
- return log_oom();
+ return -ENOMEM;
r = loop_write(fd, packet, n + 1, true);
if (r < 0)
@@ -132,7 +129,7 @@ static int ask_password_plymouth(
if (flag_file && access(flag_file, F_OK) < 0)
return -errno;
- j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for);
+ j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for);
if (j < 0) {
if (errno == EINTR)
continue;
@@ -141,15 +138,20 @@ static int ask_password_plymouth(
} else if (j == 0)
return -ETIME;
- if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0)
+ if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
flush_fd(notify);
if (pollfd[POLL_SOCKET].revents == 0)
continue;
k = read(fd, buffer + p, sizeof(buffer) - p);
- if (k <= 0)
- return r = k < 0 ? -errno : -EIO;
+ if (k < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
+ return -errno;
+ } else if (k == 0)
+ return -EIO;
p += k;
@@ -158,7 +160,7 @@ static int ask_password_plymouth(
if (buffer[0] == 5) {
- if (accept_cached) {
+ if (flags & ASK_PASSWORD_ACCEPT_CACHED) {
/* Hmm, first try with cached
* passwords failed, so let's retry
* with a normal password request */
@@ -171,7 +173,7 @@ static int ask_password_plymouth(
if (r < 0)
return r;
- accept_cached = false;
+ flags &= ~ASK_PASSWORD_ACCEPT_CACHED;
p = 0;
continue;
}
@@ -199,7 +201,7 @@ static int ask_password_plymouth(
if (!l)
return -ENOMEM;
- *_passphrases = l;
+ *ret = l;
break;
} else
@@ -257,7 +259,7 @@ static int parse_password(const char *filename, char **wall) {
if (asprintf(&_wall,
"%s%sPassword entry required for \'%s\' (PID %u).\r\n"
"Please enter password with the systemd-tty-ask-password-agent tool!",
- *wall ? *wall : "",
+ strempty(*wall),
*wall ? "\r\n\r\n" : "",
message,
pid) < 0)
@@ -284,7 +286,7 @@ static int parse_password(const char *filename, char **wall) {
if (arg_plymouth) {
_cleanup_strv_free_ char **passwords = NULL;
- r = ask_password_plymouth(message, not_after, filename, accept_cached, &passwords);
+ r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords);
if (r >= 0) {
char **p;
@@ -306,19 +308,23 @@ static int parse_password(const char *filename, char **wall) {
}
} else {
- int tty_fd = -1;
_cleanup_free_ char *password = NULL;
+ int tty_fd = -1;
if (arg_console) {
tty_fd = acquire_terminal("/dev/console", false, false, false, USEC_INFINITY);
if (tty_fd < 0)
- return tty_fd;
+ return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m");
+
+ r = reset_terminal_fd(tty_fd, true);
+ if (r < 0)
+ log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
}
- r = ask_password_tty(message, not_after, echo, filename, &password);
+ r = ask_password_tty(message, NULL, not_after, echo ? ASK_PASSWORD_ECHO : 0, filename, &password);
if (arg_console) {
- safe_close(tty_fd);
+ tty_fd = safe_close(tty_fd);
release_terminal();
}
@@ -348,12 +354,9 @@ static int parse_password(const char *filename, char **wall) {
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa,
- offsetof(struct sockaddr_un, sun_path) + strlen(socket_name));
- if (r < 0) {
- log_error_errno(errno, "Failed to send: %m");
- return r;
- }
+ r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name));
+ if (r < 0)
+ return log_error_errno(errno, "Failed to send: %m");
}
return 0;
@@ -361,40 +364,45 @@ static int parse_password(const char *filename, char **wall) {
static int wall_tty_block(void) {
_cleanup_free_ char *p = NULL;
- int fd, r;
dev_t devnr;
+ int fd, r;
r = get_ctty_devnr(0, &devnr);
+ if (r == -ENXIO) /* We have no controlling tty */
+ return -ENOTTY;
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to get controlling TTY: %m");
if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0)
- return -ENOMEM;
+ return log_oom();
mkdir_parents_label(p, 0700);
mkfifo(p, 0600);
fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (fd < 0)
- return -errno;
+ return log_debug_errno(errno, "Failed to open %s: %m", p);
return fd;
}
static bool wall_tty_match(const char *path, void *userdata) {
- int fd, r;
- struct stat st;
_cleanup_free_ char *p = NULL;
+ _cleanup_close_ int fd = -1;
+ struct stat st;
if (!path_is_absolute(path))
path = strjoina("/dev/", path);
- r = lstat(path, &st);
- if (r < 0)
+ if (lstat(path, &st) < 0) {
+ log_debug_errno(errno, "Failed to stat %s: %m", path);
return true;
+ }
- if (!S_ISCHR(st.st_mode))
+ if (!S_ISCHR(st.st_mode)) {
+ log_debug("%s is not a character device.", path);
return true;
+ }
/* We use named pipes to ensure that wall messages suggesting
* password entry are not printed over password prompts
@@ -404,16 +412,19 @@ static bool wall_tty_match(const char *path, void *userdata) {
* advantage that the block will automatically go away if the
* process dies. */
- if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
+ if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) {
+ log_oom();
return true;
+ }
fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (fd < 0)
- return true;
+ if (fd < 0) {
+ log_debug_errno(errno, "Failed top open the wall pipe: %m");
+ return 1;
+ }
/* What, we managed to open the pipe? Then this tty is filtered. */
- safe_close(fd);
- return false;
+ return 0;
}
static int show_passwords(void) {
@@ -426,11 +437,10 @@ static int show_passwords(void) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "opendir(/run/systemd/ask-password): %m");
- return -errno;
+ return log_error_errno(errno, "Failed top open /run/systemd/ask-password: %m");
}
- while ((de = readdir(d))) {
+ FOREACH_DIRENT_ALL(de, d, return log_error_errno(errno, "Failed to read directory: %m")) {
_cleanup_free_ char *p = NULL, *wall = NULL;
int q;
@@ -455,7 +465,7 @@ static int show_passwords(void) {
r = q;
if (wall)
- utmp_wall(wall, NULL, NULL, wall_tty_match, NULL);
+ (void) utmp_wall(wall, NULL, NULL, wall_tty_match, NULL);
}
return r;
@@ -475,14 +485,14 @@ static int watch_passwords(void) {
tty_block_fd = wall_tty_block();
- mkdir_p_label("/run/systemd/ask-password", 0755);
+ (void) mkdir_p_label("/run/systemd/ask-password", 0755);
notify = inotify_init1(IN_CLOEXEC);
if (notify < 0)
- return -errno;
+ return log_error_errno(errno, "Failed to allocate directory watch: %m");
if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0)
- return -errno;
+ return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: %m");
assert_se(sigemptyset(&mask) >= 0);
assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0);
@@ -490,7 +500,7 @@ static int watch_passwords(void) {
signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
if (signal_fd < 0)
- return -errno;
+ return log_error_errno(errno, "Failed to allocate signal file descriptor: %m");
pollfd[FD_INOTIFY].fd = notify;
pollfd[FD_INOTIFY].events = POLLIN;
@@ -510,7 +520,7 @@ static int watch_passwords(void) {
}
if (pollfd[FD_INOTIFY].revents != 0)
- flush_fd(notify);
+ (void) flush_fd(notify);
if (pollfd[FD_SIGNAL].revents != 0)
break;
@@ -571,9 +581,7 @@ static int parse_argv(int argc, char *argv[]) {
return 0;
case ARG_VERSION:
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
- return 0;
+ return version();
case ARG_LIST:
arg_action = ACTION_LIST;
@@ -628,8 +636,8 @@ int main(int argc, char *argv[]) {
goto finish;
if (arg_console) {
- setsid();
- release_terminal();
+ (void) setsid();
+ (void) release_terminal();
}
if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL))
@@ -637,9 +645,6 @@ int main(int argc, char *argv[]) {
else
r = show_passwords();
- if (r < 0)
- log_error_errno(r, "Error: %m");
-
finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/udev/.gitignore b/src/udev/.gitignore
index ba112ce218..f5d8be3dc1 100644
--- a/src/udev/.gitignore
+++ b/src/udev/.gitignore
@@ -1,5 +1,4 @@
/udev.pc
/keyboard-keys-from-name.gperf
/keyboard-keys-from-name.h
-/keyboard-keys-to-name.h
/keyboard-keys-list.txt
diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c
index e265aa5f53..1d1798dd10 100644
--- a/src/udev/ata_id/ata_id.c
+++ b/src/udev/ata_id/ata_id.c
@@ -473,7 +473,7 @@ int main(int argc, char *argv[])
disk_identify_fixup_string(identify.byte, 27, 40); /* model */
disk_identify_fixup_uint16(identify.byte, 0); /* configuration */
disk_identify_fixup_uint16(identify.byte, 75); /* queue depth */
- disk_identify_fixup_uint16(identify.byte, 75); /* SATA capabilities */
+ disk_identify_fixup_uint16(identify.byte, 76); /* SATA capabilities */
disk_identify_fixup_uint16(identify.byte, 82); /* command set supported */
disk_identify_fixup_uint16(identify.byte, 83); /* command set supported */
disk_identify_fixup_uint16(identify.byte, 84); /* command set supported */
@@ -484,6 +484,10 @@ int main(int argc, char *argv[])
disk_identify_fixup_uint16(identify.byte, 90); /* time required for enhanced SECURITY ERASE UNIT */
disk_identify_fixup_uint16(identify.byte, 91); /* current APM values */
disk_identify_fixup_uint16(identify.byte, 94); /* current AAM value */
+ disk_identify_fixup_uint16(identify.byte, 108); /* WWN */
+ disk_identify_fixup_uint16(identify.byte, 109); /* WWN */
+ disk_identify_fixup_uint16(identify.byte, 110); /* WWN */
+ disk_identify_fixup_uint16(identify.byte, 111); /* WWN */
disk_identify_fixup_uint16(identify.byte, 128); /* device lock function */
disk_identify_fixup_uint16(identify.byte, 217); /* nominal media rotation rate */
memcpy(&id, identify.byte, sizeof id);
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 63e54db56e..4b8c5053a4 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -460,6 +460,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
mac = &generated_mac;
}
break;
+ case MACPOLICY_NONE:
default:
mac = config->mac;
}
@@ -492,7 +493,8 @@ int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret
static const char* const mac_policy_table[_MACPOLICY_MAX] = {
[MACPOLICY_PERSISTENT] = "persistent",
- [MACPOLICY_RANDOM] = "random"
+ [MACPOLICY_RANDOM] = "random",
+ [MACPOLICY_NONE] = "none"
};
DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index 9875057e84..c52db2ce55 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -32,6 +32,7 @@ typedef struct link_config link_config;
typedef enum MACPolicy {
MACPOLICY_PERSISTENT,
MACPOLICY_RANDOM,
+ MACPOLICY_NONE,
_MACPOLICY_MAX,
_MACPOLICY_INVALID = -1
} MACPolicy;
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 98c33171d4..10bf3880b0 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -1937,7 +1937,8 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
break;
}
}
- if (!match && (cur->key.op != OP_NOMATCH))
+ if ((!match && (cur->key.op != OP_NOMATCH)) ||
+ (match && (cur->key.op == OP_NOMATCH)))
goto nomatch;
break;
}
@@ -2514,7 +2515,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
r = sysctl_write(filename, value);
if (r < 0)
- log_error("error writing SYSCTL{%s}='%s': %s", filename, value, strerror(-r));
+ log_error_errno(r, "error writing SYSCTL{%s}='%s': %m", filename, value);
break;
}
case TK_A_RUN_BUILTIN:
diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c
index 79f45610db..3d6ca7a985 100644
--- a/src/udev/udevadm-settle.c
+++ b/src/udev/udevadm-settle.c
@@ -65,10 +65,9 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) {
r = safe_atou(optarg, &timeout);
if (r < 0) {
- fprintf(stderr, "Invalid timeout value '%s': %s\n",
- optarg, strerror(-r));
- exit(EXIT_FAILURE);
- };
+ log_error_errno(r, "Invalid timeout value '%s': %m", optarg);
+ return EXIT_FAILURE;
+ }
break;
}
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 20497ae8be..e4d2f47745 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -18,44 +18,45 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <stddef.h>
-#include <signal.h>
-#include <unistd.h>
#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdbool.h>
#include <string.h>
-#include <fcntl.h>
-#include <getopt.h>
+#include <sys/epoll.h>
#include <sys/file.h>
-#include <sys/time.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
#include <sys/prctl.h>
-#include <sys/socket.h>
#include <sys/signalfd.h>
-#include <sys/epoll.h>
-#include <sys/mount.h>
-#include <sys/wait.h>
+#include <sys/socket.h>
#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/inotify.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <unistd.h>
#include "sd-daemon.h"
#include "sd-event.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-#include "event-util.h"
-#include "netlink-util.h"
#include "cgroup-util.h"
-#include "process-util.h"
+#include "cpu-set-util.h"
#include "dev-setup.h"
+#include "event-util.h"
#include "fileio.h"
-#include "selinux-util.h"
-#include "udev.h"
-#include "udev-util.h"
#include "formats-util.h"
#include "hashmap.h"
+#include "netlink-util.h"
+#include "process-util.h"
+#include "selinux-util.h"
+#include "signal-util.h"
+#include "terminal-util.h"
+#include "udev-util.h"
+#include "udev.h"
static bool arg_debug = false;
static int arg_daemonize = false;
diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c
index b2998dce43..bcabf65a36 100644
--- a/src/update-utmp/update-utmp.c
+++ b/src/update-utmp/update-utmp.c
@@ -62,7 +62,7 @@ static usec_t get_startup_time(Context *c) {
&error,
't', &t);
if (r < 0) {
- log_error("Failed to get timestamp: %s", bus_error_message(&error, -r));
+ log_error_errno(r, "Failed to get timestamp: %s", bus_error_message(&error, r));
return 0;
}
@@ -105,10 +105,8 @@ static int get_current_runlevel(Context *c) {
"ActiveState",
&error,
&state);
- if (r < 0) {
- log_warning("Failed to get state: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_warning_errno(r, "Failed to get state: %s", bus_error_message(&error, r));
if (streq(state, "active") || streq(state, "reloading"))
return table[i].runlevel;
@@ -130,8 +128,7 @@ static int on_reboot(Context *c) {
if (c->audit_fd >= 0)
if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
errno != EPERM) {
- r = log_error_errno(errno,
- "Failed to send audit message: %m");
+ r = log_error_errno(errno, "Failed to send audit message: %m");
}
#endif
@@ -160,8 +157,7 @@ static int on_shutdown(Context *c) {
if (c->audit_fd >= 0)
if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 &&
errno != EPERM) {
- r = log_error_errno(errno,
- "Failed to send audit message: %m");
+ r = log_error_errno(errno, "Failed to send audit message: %m");
}
#endif
@@ -211,8 +207,7 @@ static int on_runlevel(Context *c) {
return log_oom();
if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 && errno != EPERM)
- r = log_error_errno(errno,
- "Failed to send audit message: %m");
+ r = log_error_errno(errno, "Failed to send audit message: %m");
}
#endif
@@ -256,7 +251,7 @@ int main(int argc, char *argv[]) {
if (c.audit_fd < 0 && errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
log_error_errno(errno, "Failed to connect to audit log: %m");
#endif
- r = bus_open_system_systemd(&c.bus);
+ r = bus_connect_system_systemd(&c.bus);
if (r < 0) {
log_error_errno(r, "Failed to get D-Bus connection: %m");
r = -EIO;
@@ -284,6 +279,6 @@ finish:
audit_close(c.audit_fd);
#endif
- sd_bus_unref(c.bus);
+ sd_bus_flush_close_unref(c.bus);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}