summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analyze/analyze.c4
-rw-r--r--src/basic/architecture.c2
-rw-r--r--src/basic/architecture.h2
-rw-r--r--src/basic/io-util.c5
-rw-r--r--src/basic/locale-util.c49
-rw-r--r--src/basic/locale-util.h24
-rw-r--r--src/basic/log.c6
-rw-r--r--src/basic/missing.h4
-rw-r--r--src/basic/socket-util.c78
-rw-r--r--src/basic/socket-util.h15
-rw-r--r--src/basic/special.h1
-rw-r--r--src/boot/bootctl.c8
-rw-r--r--src/cgroups-agent/cgroups-agent.c48
-rw-r--r--src/core/cgroup.c19
-rw-r--r--src/core/dbus-job.c2
-rw-r--r--src/core/dbus-manager.c103
-rw-r--r--src/core/dbus-socket.c2
-rw-r--r--src/core/dbus.c75
-rw-r--r--src/core/dbus.h2
-rw-r--r--src/core/execute.c2
-rw-r--r--src/core/job.c24
-rw-r--r--src/core/job.h2
-rw-r--r--src/core/load-fragment.c26
-rw-r--r--src/core/manager.c166
-rw-r--r--src/core/manager.h3
-rw-r--r--src/core/mount.c37
-rw-r--r--src/core/namespace.c12
-rw-r--r--src/core/org.freedesktop.systemd1.conf4
-rw-r--r--src/core/socket.c209
-rw-r--r--src/core/transaction.c2
-rw-r--r--src/core/unit.c18
-rw-r--r--src/core/unit.h1
-rw-r--r--src/coredump/coredump.c9
-rw-r--r--src/delta/delta.c20
-rw-r--r--src/firstboot/firstboot.c8
-rw-r--r--src/fsck/fsck.c2
-rw-r--r--src/fstab-generator/fstab-generator.c8
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c6
-rw-r--r--src/import/importd.c2
-rw-r--r--src/journal/journal-send.c14
-rw-r--r--src/journal/journald-native.c14
-rw-r--r--src/journal/journald-server.c2
-rw-r--r--src/journal/journald-stream.c13
-rw-r--r--src/journal/journald-syslog.c36
-rw-r--r--src/libsystemd-network/network-internal.c141
-rw-r--r--src/libsystemd-network/network-internal.h4
-rw-r--r--src/libsystemd/sd-bus/bus-dump.c2
-rw-r--r--src/libsystemd/sd-bus/busctl.c51
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c2
-rw-r--r--src/libsystemd/sd-daemon/sd-daemon.c4
-rw-r--r--src/login/logind-dbus.c49
-rw-r--r--src/login/logind-gperf.gperf2
-rw-r--r--src/login/logind-inhibit.c2
-rw-r--r--src/login/logind-seat-dbus.c2
-rw-r--r--src/login/logind-session-dbus.c49
-rw-r--r--src/login/logind-session.c21
-rw-r--r--src/login/logind-session.h4
-rw-r--r--src/login/logind-user-dbus.c2
-rw-r--r--src/login/logind.c6
-rw-r--r--src/login/logind.conf.in2
-rw-r--r--src/login/logind.h2
-rw-r--r--src/login/org.freedesktop.login1.conf4
-rw-r--r--src/login/pam_systemd.c2
-rw-r--r--src/login/sysfs-show.c8
-rw-r--r--src/network/networkctl.c4
-rw-r--r--src/network/networkd-address.c27
-rw-r--r--src/network/networkd-conf.c2
-rw-r--r--src/network/networkd-link.c16
-rw-r--r--src/network/networkd-link.h2
-rw-r--r--src/network/networkd-lldp-tx.c102
-rw-r--r--src/network/networkd-lldp-tx.h14
-rw-r--r--src/network/networkd-netdev-bridge.c7
-rw-r--r--src/network/networkd-netdev-bridge.h1
-rw-r--r--src/network/networkd-netdev-gperf.gperf1
-rw-r--r--src/network/networkd-netdev.c2
-rw-r--r--src/network/networkd-network-gperf.gperf4
-rw-r--r--src/network/networkd-network.h3
-rw-r--r--src/network/networkd-route.c2
-rw-r--r--src/network/networkd.h1
-rw-r--r--src/network/test-networkd-conf.c4
-rw-r--r--src/nspawn/nspawn-gperf.gperf3
-rw-r--r--src/nspawn/nspawn-network.c187
-rw-r--r--src/nspawn/nspawn-network.h3
-rw-r--r--src/nspawn/nspawn-settings.c40
-rw-r--r--src/nspawn/nspawn-settings.h2
-rw-r--r--src/nspawn/nspawn.c90
-rw-r--r--src/reply-password/reply-password.c8
-rw-r--r--src/shared/ask-password-api.c2
-rw-r--r--src/shared/bus-unit-util.c12
-rw-r--r--src/shared/cgroup-show.c10
-rw-r--r--src/shared/conf-parser.c38
-rw-r--r--src/shared/conf-parser.h1
-rw-r--r--src/shared/firewall-util.c6
-rw-r--r--src/shared/generator.c16
-rw-r--r--src/shared/generator.h4
-rw-r--r--src/shared/install.c83
-rw-r--r--src/shared/install.h1
-rw-r--r--src/socket-proxy/socket-proxyd.c17
-rw-r--r--src/systemctl/systemctl.c54
-rw-r--r--src/test/test-socket-util.c42
-rw-r--r--src/tty-ask-password-agent/tty-ask-password-agent.c7
-rw-r--r--src/udev/udev-ctrl.c2
-rw-r--r--src/vconsole/vconsole-setup.c8
103 files changed, 1606 insertions, 670 deletions
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index a790ccd33e..d621f66aec 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -752,9 +752,9 @@ static int list_dependencies_print(const char *name, unsigned int level, unsigne
char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX];
for (i = level; i != 0; i--)
- printf("%s", draw_special_char(branches & (1 << (i-1)) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE));
+ printf("%s", special_glyph(branches & (1 << (i-1)) ? TREE_VERTICAL : TREE_SPACE));
- printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
+ printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH));
if (times) {
if (times->time)
diff --git a/src/basic/architecture.c b/src/basic/architecture.c
index 8e2c2b02d2..b1c8e91f50 100644
--- a/src/basic/architecture.c
+++ b/src/basic/architecture.c
@@ -63,7 +63,7 @@ int uname_architecture(void) {
#elif defined(__s390__) || defined(__s390x__)
{ "s390x", ARCHITECTURE_S390X },
{ "s390", ARCHITECTURE_S390 },
-#elif defined(__sparc__) || defined(__sparc64__)
+#elif defined(__sparc__)
{ "sparc64", ARCHITECTURE_SPARC64 },
{ "sparc", ARCHITECTURE_SPARC },
#elif defined(__mips__) || defined(__mips64__)
diff --git a/src/basic/architecture.h b/src/basic/architecture.h
index 91ec108e04..b3e4d85906 100644
--- a/src/basic/architecture.h
+++ b/src/basic/architecture.h
@@ -116,7 +116,7 @@ int uname_architecture(void);
#elif defined(__s390__)
# define native_architecture() ARCHITECTURE_S390
# define LIB_ARCH_TUPLE "s390-linux-gnu"
-#elif defined(__sparc64__)
+#elif defined(__sparc__) && defined (__arch64__)
# define native_architecture() ARCHITECTURE_SPARC64
# define LIB_ARCH_TUPLE "sparc64-linux-gnu"
#elif defined(__sparc__)
diff --git a/src/basic/io-util.c b/src/basic/io-util.c
index 0037a37f2a..cc6dfa8c1b 100644
--- a/src/basic/io-util.c
+++ b/src/basic/io-util.c
@@ -33,6 +33,11 @@ int flush_fd(int fd) {
.events = POLLIN,
};
+ /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
+ * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
+ * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
+ * was set to non-blocking too. */
+
for (;;) {
char buf[LINE_MAX];
ssize_t l;
diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c
index eaad25e65b..ada0a28cd8 100644
--- a/src/basic/locale-util.c
+++ b/src/basic/locale-util.c
@@ -271,34 +271,35 @@ out:
}
-const char *draw_special_char(DrawSpecialChar ch) {
-
- static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
-
- /* UTF-8 */ {
- [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */
- [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
- [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
- [DRAW_TREE_SPACE] = " ", /* */
- [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */
- [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */
- [DRAW_ARROW] = "\342\206\222", /* → */
- [DRAW_DASH] = "\342\200\223", /* – */
+const char *special_glyph(SpecialGlyph code) {
+
+ static const char* const draw_table[2][_SPECIAL_GLYPH_MAX] = {
+ /* ASCII fallback */
+ [false] = {
+ [TREE_VERTICAL] = "| ",
+ [TREE_BRANCH] = "|-",
+ [TREE_RIGHT] = "`-",
+ [TREE_SPACE] = " ",
+ [TRIANGULAR_BULLET] = ">",
+ [BLACK_CIRCLE] = "*",
+ [ARROW] = "->",
+ [MDASH] = "-",
},
- /* ASCII fallback */ {
- [DRAW_TREE_VERTICAL] = "| ",
- [DRAW_TREE_BRANCH] = "|-",
- [DRAW_TREE_RIGHT] = "`-",
- [DRAW_TREE_SPACE] = " ",
- [DRAW_TRIANGULAR_BULLET] = ">",
- [DRAW_BLACK_CIRCLE] = "*",
- [DRAW_ARROW] = "->",
- [DRAW_DASH] = "-",
- }
+ /* UTF-8 */
+ [ true ] = {
+ [TREE_VERTICAL] = "\342\224\202 ", /* │ */
+ [TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
+ [TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
+ [TREE_SPACE] = " ", /* */
+ [TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */
+ [BLACK_CIRCLE] = "\342\227\217", /* ● */
+ [ARROW] = "\342\206\222", /* → */
+ [MDASH] = "\342\200\223", /* – */
+ },
};
- return draw_table[!is_locale_utf8()][ch];
+ return draw_table[is_locale_utf8()][code];
}
static const char * const locale_variable_table[_VARIABLE_LC_MAX] = {
diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h
index b0f9679286..0630a034ab 100644
--- a/src/basic/locale-util.h
+++ b/src/basic/locale-util.h
@@ -55,19 +55,19 @@ void init_gettext(void);
bool is_locale_utf8(void);
-typedef enum DrawSpecialChar {
- DRAW_TREE_VERTICAL,
- DRAW_TREE_BRANCH,
- DRAW_TREE_RIGHT,
- DRAW_TREE_SPACE,
- DRAW_TRIANGULAR_BULLET,
- DRAW_BLACK_CIRCLE,
- DRAW_ARROW,
- DRAW_DASH,
- _DRAW_SPECIAL_CHAR_MAX
-} DrawSpecialChar;
+typedef enum {
+ TREE_VERTICAL,
+ TREE_BRANCH,
+ TREE_RIGHT,
+ TREE_SPACE,
+ TRIANGULAR_BULLET,
+ BLACK_CIRCLE,
+ ARROW,
+ MDASH,
+ _SPECIAL_GLYPH_MAX
+} SpecialGlyph;
-const char *draw_special_char(DrawSpecialChar ch);
+const char *special_glyph(SpecialGlyph code) _const_;
const char* locale_variable_to_string(LocaleVariable i) _const_;
LocaleVariable locale_variable_from_string(const char *s) _pure_;
diff --git a/src/basic/log.c b/src/basic/log.c
index d89e6f7274..3ea643b6e6 100644
--- a/src/basic/log.c
+++ b/src/basic/log.c
@@ -165,7 +165,7 @@ static int log_open_syslog(void) {
goto fail;
}
- if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
safe_close(syslog_fd);
/* Some legacy syslog systems still use stream
@@ -177,7 +177,7 @@ static int log_open_syslog(void) {
goto fail;
}
- if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
@@ -215,7 +215,7 @@ static int log_open_journal(void) {
goto fail;
}
- if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 22ea8f67cc..651e414395 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -389,6 +389,10 @@ struct btrfs_ioctl_quota_ctl_args {
struct btrfs_ioctl_qgroup_limit_args)
#endif
+#ifndef BTRFS_IOC_QUOTA_RESCAN_WAIT
+#define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46)
+#endif
+
#ifndef BTRFS_FIRST_FREE_OBJECTID
#define BTRFS_FIRST_FREE_OBJECTID 256
#endif
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 0f38f9a0f3..c8769a54f4 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -23,6 +23,7 @@
#include <net/if.h>
#include <netdb.h>
#include <netinet/ip.h>
+#include <poll.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -42,7 +43,9 @@
#include "socket-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
#include "user-util.h"
+#include "utf8.h"
#include "util.h"
int socket_address_parse(SocketAddress *a, const char *s) {
@@ -794,6 +797,42 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
+bool ifname_valid(const char *p) {
+ bool numeric = true;
+
+ /* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
+ * but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We
+ * also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
+
+ if (isempty(p))
+ return false;
+
+ if (strlen(p) >= IFNAMSIZ)
+ return false;
+
+ if (STR_IN_SET(p, ".", ".."))
+ return false;
+
+ while (*p) {
+ if ((unsigned char) *p >= 127U)
+ return false;
+
+ if ((unsigned char) *p <= 32U)
+ return false;
+
+ if (*p == ':' || *p == '/')
+ return false;
+
+ numeric = numeric && (*p >= '0' && *p <= '9');
+ p++;
+ }
+
+ if (numeric)
+ return false;
+
+ return true;
+}
+
int getpeercred(int fd, struct ucred *ucred) {
socklen_t n = sizeof(struct ucred);
struct ucred u;
@@ -970,3 +1009,42 @@ fallback:
return (ssize_t) k;
}
+
+int flush_accept(int fd) {
+
+ struct pollfd pollfd = {
+ .fd = fd,
+ .events = POLLIN,
+ };
+ int r;
+
+
+ /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */
+
+ for (;;) {
+ int cfd;
+
+ r = poll(&pollfd, 1, 0);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+
+ return -errno;
+
+ } else if (r == 0)
+ return 0;
+
+ cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
+ if (cfd < 0) {
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EAGAIN)
+ return 0;
+
+ return -errno;
+ }
+
+ close(cfd);
+ }
+}
diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h
index d17a2f35f8..e9230e4a9f 100644
--- a/src/basic/socket-util.h
+++ b/src/basic/socket-util.h
@@ -123,6 +123,8 @@ int fd_inc_rcvbuf(int fd, size_t n);
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
+bool ifname_valid(const char *p);
+
int getpeercred(int fd, struct ucred *ucred);
int getpeersec(int fd, char **ret);
@@ -135,5 +137,18 @@ int receive_one_fd(int transport_fd, int flags);
ssize_t next_datagram_size_fd(int fd);
+int flush_accept(int fd);
+
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
+
+/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
+#define SOCKADDR_UN_LEN(sa) \
+ ({ \
+ const struct sockaddr_un *_sa = &(sa); \
+ assert(_sa->sun_family == AF_UNIX); \
+ offsetof(struct sockaddr_un, sun_path) + \
+ (_sa->sun_path[0] == 0 ? \
+ 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \
+ strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \
+ })
diff --git a/src/basic/special.h b/src/basic/special.h
index 2fd03d9f75..084d3dfa23 100644
--- a/src/basic/special.h
+++ b/src/basic/special.h
@@ -52,6 +52,7 @@
#define SPECIAL_LOCAL_FS_TARGET "local-fs.target"
#define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target"
#define SPECIAL_INITRD_FS_TARGET "initrd-fs.target"
+#define SPECIAL_INITRD_ROOT_DEVICE_TARGET "initrd-root-device.target"
#define SPECIAL_INITRD_ROOT_FS_TARGET "initrd-root-fs.target"
#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */
#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target"
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index e9baf69f6a..d0af41498f 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -266,9 +266,9 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char
if (r < 0)
return r;
if (r > 0)
- printf(" File: %s/%s/%s (%s)\n", draw_special_char(DRAW_TREE_RIGHT), path, de->d_name, v);
+ printf(" File: %s/%s/%s (%s)\n", special_glyph(TREE_RIGHT), path, de->d_name, v);
else
- printf(" File: %s/%s/%s\n", draw_special_char(DRAW_TREE_RIGHT), path, de->d_name);
+ printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT), path, de->d_name);
c++;
}
@@ -320,7 +320,7 @@ static int print_efi_option(uint16_t id, bool in_order) {
printf(" ID: 0x%04X\n", id);
printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition));
- printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), path);
+ printf(" File: %s%s\n", special_glyph(TREE_RIGHT), path);
printf("\n");
return 0;
@@ -1077,7 +1077,7 @@ static int bootctl_main(int argc, char*argv[]) {
SD_ID128_FORMAT_VAL(loader_part_uuid));
else
printf(" Partition: n/a\n");
- printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(loader_path));
+ printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
printf("\n");
} else
printf("System:\n Not booted with EFI\n");
diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c
index aadfba0707..d7c722ac3d 100644
--- a/src/cgroups-agent/cgroups-agent.c
+++ b/src/cgroups-agent/cgroups-agent.c
@@ -18,15 +18,22 @@
***/
#include <stdlib.h>
+#include <sys/socket.h>
-#include "sd-bus.h"
-
-#include "bus-util.h"
+#include "fd-util.h"
#include "log.h"
+#include "socket-util.h"
int main(int argc, char *argv[]) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- int r;
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/cgroups-agent",
+ };
+
+ _cleanup_close_ int fd = -1;
+ ssize_t n;
+ size_t l;
if (argc != 2) {
log_error("Incorrect number of arguments.");
@@ -37,27 +44,22 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- /* We send this event to the private D-Bus socket and then the
- * system instance will forward this to the system bus. We do
- * this to avoid an activation loop when we start dbus when we
- * are called when the dbus service is shut down. */
-
- r = bus_connect_system_systemd(&bus);
- if (r < 0) {
- /* If we couldn't connect we assume this was triggered
- * while systemd got restarted/transitioned from
- * initrd to the system, so let's ignore this */
- log_debug_errno(r, "Failed to get D-Bus connection: %m");
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ log_debug_errno(errno, "Failed to allocate socket: %m");
+ return EXIT_FAILURE;
+ }
+
+ l = strlen(argv[1]);
+
+ n = sendto(fd, argv[1], l, 0, &sa.sa, SOCKADDR_UN_LEN(sa.un));
+ if (n < 0) {
+ log_debug_errno(errno, "Failed to send cgroups agent message: %m");
return EXIT_FAILURE;
}
- r = sd_bus_emit_signal(bus,
- "/org/freedesktop/systemd1/agent",
- "org.freedesktop.systemd1.Agent",
- "Released",
- "s", argv[1]);
- if (r < 0) {
- log_debug_errno(r, "Failed to send signal message on private connection: %m");
+ if ((size_t) n != l) {
+ log_debug("Datagram size mismatch");
return EXIT_FAILURE;
}
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 44106e52ea..4f1637ffe9 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -996,6 +996,7 @@ static int unit_create_cgroup(
/* Keep track that this is now realized */
u->cgroup_realized = true;
u->cgroup_realized_mask = target_mask;
+ u->cgroup_enabled_mask = enable_mask;
if (u->type != UNIT_SLICE && !c->delegate) {
@@ -1025,10 +1026,10 @@ int unit_attach_pids_to_cgroup(Unit *u) {
return 0;
}
-static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask) {
+static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask, CGroupMask enable_mask) {
assert(u);
- return u->cgroup_realized && u->cgroup_realized_mask == target_mask;
+ return u->cgroup_realized && u->cgroup_realized_mask == target_mask && u->cgroup_enabled_mask == enable_mask;
}
/* Check if necessary controllers and attributes for a unit are in place.
@@ -1049,7 +1050,9 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
}
target_mask = unit_get_target_mask(u);
- if (unit_has_mask_realized(u, target_mask))
+ enable_mask = unit_get_enable_mask(u);
+
+ if (unit_has_mask_realized(u, target_mask, enable_mask))
return 0;
/* First, realize parents */
@@ -1060,7 +1063,6 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
}
/* And then do the real work */
- enable_mask = unit_get_enable_mask(u);
r = unit_create_cgroup(u, target_mask, enable_mask);
if (r < 0)
return r;
@@ -1129,7 +1131,7 @@ static void unit_queue_siblings(Unit *u) {
/* If the unit doesn't need any new controllers
* and has current ones realized, it doesn't need
* any changes. */
- if (unit_has_mask_realized(m, unit_get_target_mask(m)))
+ if (unit_has_mask_realized(m, unit_get_target_mask(m), unit_get_enable_mask(m)))
continue;
unit_add_to_cgroup_queue(m);
@@ -1208,6 +1210,7 @@ void unit_prune_cgroup(Unit *u) {
u->cgroup_realized = false;
u->cgroup_realized_mask = 0;
+ u->cgroup_enabled_mask = 0;
}
int unit_search_main_pid(Unit *u, pid_t *ret) {
@@ -1451,7 +1454,9 @@ int manager_setup_cgroup(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to watch control group inotify object: %m");
- r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_IDLE - 5);
+ /* Process cgroup empty notifications early, but after service notifications and SIGCHLD. Also
+ * see handling of cgroup agent notifications, for the classic cgroup hierarchy support. */
+ r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_NORMAL-5);
if (r < 0)
return log_error_errno(r, "Failed to set priority of inotify event source: %m");
@@ -1597,6 +1602,8 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
assert(m);
assert(cgroup);
+ log_debug("Got cgroup empty notification for: %s", cgroup);
+
u = manager_get_unit_by_cgroup(m, cgroup);
if (!u)
return 0;
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index 97a93fb2f1..ccf7453d47 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -75,7 +75,7 @@ int bus_job_method_cancel(sd_bus_message *message, void *userdata, sd_bus_error
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
- job_finish_and_invalidate(j, JOB_CANCELED, true);
+ job_finish_and_invalidate(j, JOB_CANCELED, true, false);
return sd_bus_reply_method_return(message, NULL);
}
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index d45f511489..86722e1162 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -642,6 +642,80 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s
return bus_unit_method_set_properties(message, u, error);
}
+static int reply_unit_info(sd_bus_message *reply, Unit *u) {
+ _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
+ Unit *following;
+
+ following = unit_following(u);
+
+ unit_path = unit_dbus_path(u);
+ if (!unit_path)
+ return -ENOMEM;
+
+ if (u->job) {
+ job_path = job_dbus_path(u->job);
+ if (!job_path)
+ return -ENOMEM;
+ }
+
+ return sd_bus_message_append(
+ reply, "(ssssssouso)",
+ u->id,
+ unit_description(u),
+ unit_load_state_to_string(u->load_state),
+ unit_active_state_to_string(unit_active_state(u)),
+ unit_sub_state_to_string(u),
+ following ? following->id : "",
+ unit_path,
+ u->job ? u->job->id : 0,
+ u->job ? job_type_to_string(u->job->type) : "",
+ job_path ? job_path : "/");
+}
+
+static int method_list_units_by_names(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ Manager *m = userdata;
+ int r;
+ char **unit;
+ _cleanup_strv_free_ char **units = NULL;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read_strv(message, &units);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_new_method_return(message, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(ssssssouso)");
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(unit, units) {
+ Unit *u;
+
+ if (!unit_name_is_valid(*unit, UNIT_NAME_ANY))
+ continue;
+
+ r = manager_load_unit(m, *unit, NULL, error, &u);
+ if (r < 0)
+ return r;
+
+ r = reply_unit_info(reply, u);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
@@ -915,14 +989,9 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e
return r;
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
- _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
- Unit *following;
-
if (k != u->id)
continue;
- following = unit_following(u);
-
if (!strv_isempty(states) &&
!strv_contains(states, unit_load_state_to_string(u->load_state)) &&
!strv_contains(states, unit_active_state_to_string(unit_active_state(u))) &&
@@ -933,28 +1002,7 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e
!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
continue;
- unit_path = unit_dbus_path(u);
- if (!unit_path)
- return -ENOMEM;
-
- if (u->job) {
- job_path = job_dbus_path(u->job);
- if (!job_path)
- return -ENOMEM;
- }
-
- r = sd_bus_message_append(
- reply, "(ssssssouso)",
- u->id,
- unit_description(u),
- unit_load_state_to_string(u->load_state),
- unit_active_state_to_string(unit_active_state(u)),
- unit_sub_state_to_string(u),
- following ? following->id : "",
- unit_path,
- u->job ? u->job->id : 0,
- u->job ? job_type_to_string(u->job->type) : "",
- job_path ? job_path : "/");
+ r = reply_unit_info(reply, u);
if (r < 0)
return r;
}
@@ -2115,6 +2163,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListUnitsFiltered", "as", "a(ssssssouso)", method_list_units_filtered, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListUnitsByPatterns", "asas", "a(ssssssouso)", method_list_units_by_patterns, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ListUnitsByNames", "as", "a(ssssssouso)", method_list_units_by_names, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index bb09a515f8..961340608d 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -149,7 +149,7 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TriggerLimitIntervalSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 263955d874..3422a02d68 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -71,28 +71,42 @@ int bus_send_queued_message(Manager *m) {
return 0;
}
+int bus_forward_agent_released(Manager *m, const char *path) {
+ int r;
+
+ assert(m);
+ assert(path);
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return 0;
+
+ if (!m->system_bus)
+ return 0;
+
+ /* If we are running a system instance we forward the agent message on the system bus, so that the user
+ * instances get notified about this, too */
+
+ r = sd_bus_emit_signal(m->system_bus,
+ "/org/freedesktop/systemd1/agent",
+ "org.freedesktop.systemd1.Agent",
+ "Released",
+ "s", path);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to propagate agent release message: %m");
+
+ return 1;
+}
+
static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- const char *cgroup, *me;
Manager *m = userdata;
+ const char *cgroup;
uid_t sender_uid;
- sd_bus *bus;
int r;
assert(message);
assert(m);
- /* ignore recursive events sent by us on the system/user bus */
- bus = sd_bus_message_get_bus(message);
- if (!sd_bus_is_server(bus)) {
- r = sd_bus_get_unique_name(bus, &me);
- if (r < 0)
- return r;
-
- if (streq_ptr(sd_bus_message_get_sender(message), me))
- return 0;
- }
-
/* only accept org.freedesktop.systemd1.Agent from UID=0 */
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
@@ -110,16 +124,6 @@ static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus
}
manager_notify_cgroup_empty(m, cgroup);
-
- /* if running as system-instance, forward under our name */
- if (MANAGER_IS_SYSTEM(m) && m->system_bus) {
- r = sd_bus_message_rewind(message, 1);
- if (r >= 0)
- r = sd_bus_send(m->system_bus, message, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to forward Released message: %m");
- }
-
return 0;
}
@@ -690,25 +694,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
- if (MANAGER_IS_SYSTEM(m)) {
- /* When we run as system instance we get the Released
- * signal via a direct connection */
-
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "interface='org.freedesktop.systemd1.Agent',"
- "member='Released',"
- "path='/org/freedesktop/systemd1/agent'",
- signal_agent_released, m);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to register Released match on new connection bus: %m");
- return 0;
- }
- }
-
r = bus_setup_disconnected_match(m, bus);
if (r < 0)
return 0;
@@ -906,8 +891,8 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
assert(m);
assert(bus);
- /* On kdbus or if we are a user instance we get the Released message via the system bus */
- if (MANAGER_IS_USER(m) || m->kdbus_fd >= 0) {
+ /* if we are a user instance we get the Released message via the system bus */
+ if (MANAGER_IS_USER(m)) {
r = sd_bus_add_match(
bus,
NULL,
@@ -990,7 +975,7 @@ static int bus_init_private(Manager *m) {
return 0;
strcpy(sa.un.sun_path, "/run/systemd/private");
- salen = offsetof(union sockaddr_union, un.sun_path) + strlen("/run/systemd/private");
+ salen = SOCKADDR_UN_LEN(sa.un);
} else {
size_t left = sizeof(sa.un.sun_path);
char *p = sa.un.sun_path;
diff --git a/src/core/dbus.h b/src/core/dbus.h
index e16a84fbb8..6baaffbd75 100644
--- a/src/core/dbus.h
+++ b/src/core/dbus.h
@@ -40,3 +40,5 @@ int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error
int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
+
+int bus_forward_agent_released(Manager *m, const char *path);
diff --git a/src/core/execute.c b/src/core/execute.c
index ac2ac39892..5eb3f13695 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -271,7 +271,7 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
}
}
- r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
r = -errno;
diff --git a/src/core/job.c b/src/core/job.c
index d9c5669c9f..7557874d4d 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -191,7 +191,7 @@ Job* job_install(Job *j) {
if (uj) {
if (job_type_is_conflicting(uj->type, j->type))
- job_finish_and_invalidate(uj, JOB_CANCELED, false);
+ job_finish_and_invalidate(uj, JOB_CANCELED, false, false);
else {
/* not conflicting, i.e. mergeable */
@@ -614,19 +614,19 @@ int job_run_and_invalidate(Job *j) {
if (j) {
if (r == -EALREADY)
- r = job_finish_and_invalidate(j, JOB_DONE, true);
+ r = job_finish_and_invalidate(j, JOB_DONE, true, true);
else if (r == -EBADR)
- r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
+ r = job_finish_and_invalidate(j, JOB_SKIPPED, true, false);
else if (r == -ENOEXEC)
- r = job_finish_and_invalidate(j, JOB_INVALID, true);
+ r = job_finish_and_invalidate(j, JOB_INVALID, true, false);
else if (r == -EPROTO)
- r = job_finish_and_invalidate(j, JOB_ASSERT, true);
+ r = job_finish_and_invalidate(j, JOB_ASSERT, true, false);
else if (r == -EOPNOTSUPP)
- r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true);
+ r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true, false);
else if (r == -EAGAIN)
job_set_state(j, JOB_WAITING);
else if (r < 0)
- r = job_finish_and_invalidate(j, JOB_FAILED, true);
+ r = job_finish_and_invalidate(j, JOB_FAILED, true, false);
}
return r;
@@ -827,11 +827,11 @@ static void job_fail_dependencies(Unit *u, UnitDependency d) {
if (!IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE))
continue;
- job_finish_and_invalidate(j, JOB_DEPENDENCY, true);
+ job_finish_and_invalidate(j, JOB_DEPENDENCY, true, false);
}
}
-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
+int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) {
Unit *u;
Unit *other;
JobType t;
@@ -848,7 +848,9 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
log_unit_debug(u, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
- job_emit_status_message(u, t, result);
+ /* If this job did nothing to respective unit we don't log the status message */
+ if (!already)
+ job_emit_status_message(u, t, result);
job_add_to_dbus_queue(j);
@@ -923,7 +925,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user
log_unit_warning(j->unit, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
u = j->unit;
- job_finish_and_invalidate(j, JOB_TIMEOUT, true);
+ job_finish_and_invalidate(j, JOB_TIMEOUT, true, false);
failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg);
diff --git a/src/core/job.h b/src/core/job.h
index 856b0ce829..d359e8bb3e 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -219,7 +219,7 @@ void job_add_to_dbus_queue(Job *j);
int job_start_timer(Job *j);
int job_run_and_invalidate(Job *j);
-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive);
+int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already);
char *job_dbus_path(Job *j);
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 9d7329e924..cea615132a 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -732,16 +732,17 @@ int config_parse_exec(
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
-int config_parse_socket_bindtodevice(const char* unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_socket_bindtodevice(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
Socket *s = data;
char *n;
@@ -752,6 +753,11 @@ int config_parse_socket_bindtodevice(const char* unit,
assert(data);
if (rvalue[0] && !streq(rvalue, "*")) {
+ if (!ifname_valid(rvalue)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is invalid, ignoring: %s", rvalue);
+ return 0;
+ }
+
n = strdup(rvalue);
if (!n)
return log_oom();
diff --git a/src/core/manager.c b/src/core/manager.c
index bd00c224f4..7838f56fd2 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -87,6 +87,7 @@
#include "watchdog.h"
#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
+#define CGROUPS_AGENT_RCVBUF_SIZE (8*1024*1024)
/* Initial delay and the interval for printing status messages about running jobs */
#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
@@ -94,6 +95,7 @@
#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
@@ -484,11 +486,11 @@ static int manager_setup_signals(Manager *m) {
(void) sd_event_source_set_description(m->signal_event_source, "manager-signal");
- /* Process signals a bit earlier than the rest of things, but
- * later than notify_fd processing, so that the notify
- * processing can still figure out to which process/service a
- * message belongs, before we reap the process. */
- r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-5);
+ /* Process signals a bit earlier than the rest of things, but later than notify_fd processing, so that the
+ * notify processing can still figure out to which process/service a message belongs, before we reap the
+ * process. Also, process this before handling cgroup notifications, so that we always collect child exit
+ * status information before detecting that there's no process in a cgroup. */
+ r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-6);
if (r < 0)
return r;
@@ -581,12 +583,12 @@ int manager_new(UnitFileScope scope, 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->cgroup_inotify_fd = -1;
+ m->pin_cgroupfs_fd = m->notify_fd = m->cgroups_agent_fd = m->signal_fd = m->time_change_fd =
+ m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd =
+ m->ask_password_inotify_fd = -1;
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
- m->ask_password_inotify_fd = -1;
m->have_ask_password = -EINVAL; /* we don't know */
m->first_boot = -1;
@@ -703,7 +705,7 @@ static int manager_setup_notify(Manager *m) {
(void) unlink(m->notify_socket);
strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1);
- r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
+ r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
@@ -722,8 +724,8 @@ static int manager_setup_notify(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to allocate notify event source: %m");
- /* Process signals a bit earlier than SIGCHLD, so that we can
- * still identify to which service an exit message belongs */
+ /* Process notification messages a bit earlier than SIGCHLD, so that we can still identify to which
+ * service an exit message belongs. */
r = sd_event_source_set_priority(m->notify_event_source, SD_EVENT_PRIORITY_NORMAL-7);
if (r < 0)
return log_error_errno(r, "Failed to set priority of notify event source: %m");
@@ -734,6 +736,79 @@ static int manager_setup_notify(Manager *m) {
return 0;
}
+static int manager_setup_cgroups_agent(Manager *m) {
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/cgroups-agent",
+ };
+ int r;
+
+ /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering
+ * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and
+ * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on
+ * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number
+ * of D-Bus connections may be queued until the kernel will start dropping further incoming connections,
+ * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX
+ * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and
+ * we thus won't lose messages.
+ *
+ * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen
+ * to it. The system instance hence listens on this special socket, but the user instances listen on the system
+ * bus for these messages. */
+
+ if (m->test_run)
+ return 0;
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return 0;
+
+ if (cg_unified() > 0) /* We don't need this anymore on the unified hierarchy */
+ return 0;
+
+ if (m->cgroups_agent_fd < 0) {
+ _cleanup_close_ int fd = -1;
+
+ /* First free all secondary fields */
+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
+
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m");
+
+ fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE);
+
+ (void) unlink(sa.un.sun_path);
+
+ /* Only allow root to connect to this socket */
+ RUN_WITH_UMASK(0077)
+ r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
+ if (r < 0)
+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
+
+ m->cgroups_agent_fd = fd;
+ fd = -1;
+ }
+
+ if (!m->cgroups_agent_event_source) {
+ r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate cgroups agent event source: %m");
+
+ /* Process cgroups notifications early, but after having processed service notification messages or
+ * SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification,
+ * and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of
+ * cgroup inotify for the unified cgroup stuff. */
+ r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m");
+
+ (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent");
+ }
+
+ return 0;
+}
+
static int manager_setup_kdbus(Manager *m) {
_cleanup_free_ char *p = NULL;
@@ -944,12 +1019,14 @@ Manager* manager_free(Manager *m) {
sd_event_source_unref(m->signal_event_source);
sd_event_source_unref(m->notify_event_source);
+ sd_event_source_unref(m->cgroups_agent_event_source);
sd_event_source_unref(m->time_change_event_source);
sd_event_source_unref(m->jobs_in_progress_event_source);
sd_event_source_unref(m->run_queue_event_source);
safe_close(m->signal_fd);
safe_close(m->notify_fd);
+ safe_close(m->cgroups_agent_fd);
safe_close(m->time_change_fd);
safe_close(m->kdbus_fd);
@@ -1142,6 +1219,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (q < 0 && r == 0)
r = q;
+ q = manager_setup_cgroups_agent(m);
+ if (q < 0 && r == 0)
+ r = q;
+
/* We might have deserialized the kdbus control fd, but if we
* didn't, then let's create the bus now. */
manager_setup_kdbus(m);
@@ -1413,7 +1494,7 @@ void manager_clear_jobs(Manager *m) {
while ((j = hashmap_first(m->jobs)))
/* No need to recurse. We're cancelling all jobs. */
- job_finish_and_invalidate(j, JOB_CANCELED, false);
+ job_finish_and_invalidate(j, JOB_CANCELED, false, false);
}
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
@@ -1479,6 +1560,35 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) {
return n;
}
+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ Manager *m = userdata;
+ char buf[PATH_MAX+1];
+ ssize_t n;
+
+ n = recv(fd, buf, sizeof(buf), 0);
+ if (n < 0)
+ return log_error_errno(errno, "Failed to read cgroups agent message: %m");
+ if (n == 0) {
+ log_error("Got zero-length cgroups agent message, ignoring.");
+ return 0;
+ }
+ if ((size_t) n >= sizeof(buf)) {
+ log_error("Got overly long cgroups agent message, ignoring.");
+ return 0;
+ }
+
+ if (memchr(buf, 0, n)) {
+ log_error("Got cgroups agent message with embedded NUL byte, ignoring.");
+ return 0;
+ }
+ buf[n] = 0;
+
+ manager_notify_cgroup_empty(m, buf);
+ bus_forward_agent_released(m, buf);
+
+ return 0;
+}
+
static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) {
_cleanup_strv_free_ char **tags = NULL;
@@ -2135,11 +2245,10 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
}
void manager_send_unit_plymouth(Manager *m, Unit *u) {
- union sockaddr_union sa = PLYMOUTH_SOCKET;
-
- int n = 0;
+ static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_free_ char *message = NULL;
_cleanup_close_ int fd = -1;
+ int n = 0;
/* Don't generate plymouth events if the service was already
* started and we're just deserializing */
@@ -2165,7 +2274,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
return;
}
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
log_error_errno(errno, "connect() failed: %m");
@@ -2265,6 +2374,16 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
fprintf(f, "notify-socket=%s\n", m->notify_socket);
}
+ if (m->cgroups_agent_fd >= 0) {
+ int copy;
+
+ copy = fdset_put_dup(fds, m->cgroups_agent_fd);
+ if (copy < 0)
+ return copy;
+
+ fprintf(f, "cgroups-agent-fd=%i\n", copy);
+ }
+
if (m->kdbus_fd >= 0) {
int copy;
@@ -2432,6 +2551,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
free(m->notify_socket);
m->notify_socket = n;
+ } else if (startswith(l, "cgroups-agent-fd=")) {
+ int fd;
+
+ if (safe_atoi(l + 17, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_debug("Failed to parse cgroups agent fd: %s", l + 10);
+ else {
+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
+ safe_close(m->cgroups_agent_fd);
+ m->cgroups_agent_fd = fdset_remove(fds, fd);
+ }
+
} else if (startswith(l, "kdbus-fd=")) {
int fd;
@@ -2552,6 +2682,10 @@ int manager_reload(Manager *m) {
if (q < 0 && r >= 0)
r = q;
+ q = manager_setup_cgroups_agent(m);
+ if (q < 0 && r >= 0)
+ r = q;
+
/* Third, fire things up! */
manager_coldplug(m);
diff --git a/src/core/manager.h b/src/core/manager.h
index f23e4056c4..6ed15c1a41 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -132,6 +132,9 @@ struct Manager {
int notify_fd;
sd_event_source *notify_event_source;
+ int cgroups_agent_fd;
+ sd_event_source *cgroups_agent_event_source;
+
int signal_fd;
sd_event_source *signal_event_source;
diff --git a/src/core/mount.c b/src/core/mount.c
index 5a8c26b9e1..665a60bb55 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -121,6 +121,20 @@ static bool mount_is_automount(const MountParameters *p) {
"x-systemd.automount\0");
}
+static bool mount_state_active(MountState state) {
+ return IN_SET(state,
+ MOUNT_MOUNTING,
+ MOUNT_MOUNTING_DONE,
+ MOUNT_REMOUNTING,
+ MOUNT_UNMOUNTING,
+ MOUNT_MOUNTING_SIGTERM,
+ MOUNT_MOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING_SIGTERM,
+ MOUNT_UNMOUNTING_SIGKILL,
+ MOUNT_REMOUNTING_SIGTERM,
+ MOUNT_REMOUNTING_SIGKILL);
+}
+
static bool needs_quota(const MountParameters *p) {
assert(p);
@@ -591,16 +605,7 @@ static void mount_set_state(Mount *m, MountState state) {
old_state = m->state;
m->state = state;
- if (state != MOUNT_MOUNTING &&
- state != MOUNT_MOUNTING_DONE &&
- state != MOUNT_REMOUNTING &&
- state != MOUNT_UNMOUNTING &&
- state != MOUNT_MOUNTING_SIGTERM &&
- state != MOUNT_MOUNTING_SIGKILL &&
- state != MOUNT_UNMOUNTING_SIGTERM &&
- state != MOUNT_UNMOUNTING_SIGKILL &&
- state != MOUNT_REMOUNTING_SIGTERM &&
- state != MOUNT_REMOUNTING_SIGKILL) {
+ if (!mount_state_active(state)) {
m->timer_event_source = sd_event_source_unref(m->timer_event_source);
mount_unwatch_control_pid(m);
m->control_command = NULL;
@@ -632,17 +637,7 @@ static int mount_coldplug(Unit *u) {
if (m->control_pid > 0 &&
pid_is_unwaited(m->control_pid) &&
- IN_SET(new_state,
- MOUNT_MOUNTING,
- MOUNT_MOUNTING_DONE,
- MOUNT_REMOUNTING,
- MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL)) {
+ mount_state_active(new_state)) {
r = unit_watch_pid(UNIT(m), m->control_pid);
if (r < 0)
diff --git a/src/core/namespace.c b/src/core/namespace.c
index b573f008b9..203d122810 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -44,6 +44,8 @@
#include "user-util.h"
#include "util.h"
+#define DEV_MOUNT_OPTIONS (MS_NOSUID|MS_STRICTATIME|MS_NOEXEC)
+
typedef enum MountMode {
/* This is ordered by priority! */
INACCESSIBLE,
@@ -153,7 +155,7 @@ static int mount_dev(BindMount *m) {
dev = strjoina(temporary_mount, "/dev");
(void) mkdir(dev, 0755);
- if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) {
+ if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
r = -errno;
goto fail;
}
@@ -237,6 +239,8 @@ static int mount_dev(BindMount *m) {
*/
(void) mkdir_p_label(m->path, 0755);
+ /* Unmount everything in old /dev */
+ umount_recursive(m->path, 0);
if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) {
r = -errno;
goto fail;
@@ -328,9 +332,11 @@ static int make_read_only(BindMount *m) {
if (IN_SET(m->mode, INACCESSIBLE, READONLY))
r = bind_remount_recursive(m->path, true);
- else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV))
+ else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV)) {
r = bind_remount_recursive(m->path, false);
- else
+ if (r == 0 && m->mode == PRIVATE_DEV) /* can be readonly but the submounts can't*/
+ r = mount(NULL, m->path, NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL);
+ } else
r = 0;
if (m->ignore && r == -ENOENT)
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
index 6c504a5e69..3c64f20872 100644
--- a/src/core/org.freedesktop.systemd1.conf
+++ b/src/core/org.freedesktop.systemd1.conf
@@ -156,6 +156,10 @@
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="ListUnitsByNames"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="StartTransientUnit"/>
<allow send_destination="org.freedesktop.systemd1"
diff --git a/src/core/socket.c b/src/core/socket.c
index d3d4866fe6..f6204d04bf 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -28,7 +28,6 @@
#include <unistd.h>
#include <linux/sctp.h>
-#include "sd-event.h"
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-util.h"
@@ -38,6 +37,7 @@
#include "exit-status.h"
#include "fd-util.h"
#include "formats-util.h"
+#include "io-util.h"
#include "label.h"
#include "log.h"
#include "missing.h"
@@ -100,7 +100,8 @@ static void socket_init(Unit *u) {
s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
- RATELIMIT_INIT(s->trigger_limit, 5*USEC_PER_SEC, 2500);
+ s->trigger_limit.interval = USEC_INFINITY;
+ s->trigger_limit.burst = (unsigned) -1;
}
static void socket_unwatch_control_pid(Socket *s) {
@@ -328,6 +329,25 @@ static int socket_add_extras(Socket *s) {
assert(s);
+ /* Pick defaults for the trigger limit, if nothing was explicitly configured. We pick a relatively high limit
+ * in Accept=yes mode, and a lower limit for Accept=no. Reason: in Accept=yes mode we are invoking accept()
+ * ourselves before the trigger limit can hit, thus incoming connections are taken off the socket queue quickly
+ * and reliably. This is different for Accept=no, where the spawned service has to take the incoming traffic
+ * off the queues, which it might not necessarily do. Moreover, while Accept=no services are supposed to
+ * process whatever is queued in one go, and thus should normally never have to be started frequently. This is
+ * different for Accept=yes where each connection is processed by a new service instance, and thus frequent
+ * service starts are typical. */
+
+ if (s->trigger_limit.interval == USEC_INFINITY)
+ s->trigger_limit.interval = 2 * USEC_PER_SEC;
+
+ if (s->trigger_limit.burst == (unsigned) -1) {
+ if (s->accept)
+ s->trigger_limit.burst = 200;
+ else
+ s->trigger_limit.burst = 20;
+ }
+
if (have_non_accept_socket(s)) {
if (!UNIT_DEREF(s->service)) {
@@ -620,8 +640,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
if (!isempty(s->user) || !isempty(s->group))
fprintf(f,
- "%sOwnerUser: %s\n"
- "%sOwnerGroup: %s\n",
+ "%sSocketUser: %s\n"
+ "%sSocketGroup: %s\n",
prefix, strna(s->user),
prefix, strna(s->group));
@@ -670,6 +690,12 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
}
+ fprintf(f,
+ "%sTriggerLimitIntervalSec: %s\n"
+ "%sTriggerLimitBurst: %u\n",
+ prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->trigger_limit.interval, USEC_PER_SEC),
+ prefix, s->trigger_limit.burst);
+
exec_context_dump(&s->exec_context, f, prefix);
kill_context_dump(&s->kill_context, f, prefix);
@@ -1221,6 +1247,45 @@ fail:
return r;
}
+static int socket_determine_selinux_label(Socket *s, char **ret) {
+ ExecCommand *c;
+ int r;
+
+ assert(s);
+ assert(ret);
+
+ if (s->selinux_context_from_net) {
+ /* If this is requested, get label from the network label */
+
+ r = mac_selinux_get_our_label(ret);
+ if (r == -EOPNOTSUPP)
+ goto no_label;
+
+ } else {
+ /* Otherwise, get it from the executable we are about to start */
+ r = socket_instantiate_service(s);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_ISSET(s->service))
+ goto no_label;
+
+ c = SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START];
+ if (!c)
+ goto no_label;
+
+ r = mac_selinux_get_create_label_from_exe(c->path, ret);
+ if (r == -EPERM || r == -EOPNOTSUPP)
+ goto no_label;
+ }
+
+ return r;
+
+no_label:
+ *ret = NULL;
+ return 0;
+}
+
static int socket_open_fds(Socket *s) {
_cleanup_(mac_selinux_freep) char *label = NULL;
bool know_label = false;
@@ -1239,46 +1304,28 @@ static int socket_open_fds(Socket *s) {
case SOCKET_SOCKET:
if (!know_label) {
- /* Figure out label, if we don't it know
- * yet. We do it once, for the first
- * socket where we need this and
- * remember it for the rest. */
-
- if (s->selinux_context_from_net) {
- /* Get it from the network label */
-
- r = mac_selinux_get_our_label(&label);
- if (r < 0 && r != -EOPNOTSUPP)
- goto rollback;
+ /* Figure out label, if we don't it know yet. We do it once, for the first socket where
+ * we need this and remember it for the rest. */
- } else {
- /* Get it from the executable we are about to start */
-
- r = socket_instantiate_service(s);
- if (r < 0)
- goto rollback;
-
- if (UNIT_ISSET(s->service) &&
- SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) {
- r = mac_selinux_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label);
- if (r < 0 && r != -EPERM && r != -EOPNOTSUPP)
- goto rollback;
- }
- }
+ r = socket_determine_selinux_label(s, &label);
+ if (r < 0)
+ goto rollback;
know_label = true;
}
/* Apply the socket protocol */
- switch(p->address.type) {
+ switch (p->address.type) {
+
case SOCK_STREAM:
case SOCK_SEQPACKET:
- if (p->socket->socket_protocol == IPPROTO_SCTP)
- p->address.protocol = p->socket->socket_protocol;
+ if (s->socket_protocol == IPPROTO_SCTP)
+ p->address.protocol = s->socket_protocol;
break;
+
case SOCK_DGRAM:
- if (p->socket->socket_protocol == IPPROTO_UDPLITE)
- p->address.protocol = p->socket->socket_protocol;
+ if (s->socket_protocol == IPPROTO_UDPLITE)
+ p->address.protocol = s->socket_protocol;
break;
}
@@ -1339,8 +1386,7 @@ static int socket_open_fds(Socket *s) {
}
break;
- case SOCKET_USB_FUNCTION:
- {
+ case SOCKET_USB_FUNCTION: {
_cleanup_free_ char *ep = NULL;
ep = path_make_absolute("ep0", p->path);
@@ -1423,6 +1469,34 @@ fail:
return r;
}
+enum {
+ SOCKET_OPEN_NONE,
+ SOCKET_OPEN_SOME,
+ SOCKET_OPEN_ALL,
+};
+
+static int socket_check_open(Socket *s) {
+ bool have_open = false, have_closed = false;
+ SocketPort *p;
+
+ assert(s);
+
+ LIST_FOREACH(port, p, s->ports) {
+ if (p->fd < 0)
+ have_closed = true;
+ else
+ have_open = true;
+
+ if (have_open && have_closed)
+ return SOCKET_OPEN_SOME;
+ }
+
+ if (have_open)
+ return SOCKET_OPEN_ALL;
+
+ return SOCKET_OPEN_NONE;
+}
+
static void socket_set_state(Socket *s, SocketState state) {
SocketState old_state;
assert(s);
@@ -1502,14 +1576,24 @@ static int socket_coldplug(Unit *u) {
SOCKET_START_CHOWN,
SOCKET_START_POST,
SOCKET_LISTENING,
- SOCKET_RUNNING,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL)) {
-
- r = socket_open_fds(s);
- if (r < 0)
- return r;
+ SOCKET_RUNNING)) {
+
+ /* Originally, we used to simply reopen all sockets here that we didn't have file descriptors
+ * for. However, this is problematic, as we won't traverse throught the SOCKET_START_CHOWN state for
+ * them, and thus the UID/GID wouldn't be right. Hence, instead simply check if we have all fds open,
+ * and if there's a mismatch, warn loudly. */
+
+ r = socket_check_open(s);
+ if (r == SOCKET_OPEN_NONE)
+ log_unit_warning(UNIT(s),
+ "Socket unit configuration has changed while unit has been running, "
+ "no open socket file descriptor left. "
+ "The socket unit is not functional until restarted.");
+ else if (r == SOCKET_OPEN_SOME)
+ log_unit_warning(UNIT(s),
+ "Socket unit configuration has changed while unit has been running, "
+ "and some socket file descriptors have not been opened yet. "
+ "The socket unit is not fully functional until restarted.");
}
if (s->deserialized_state == SOCKET_LISTENING) {
@@ -1882,6 +1966,21 @@ fail:
socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
}
+static void flush_ports(Socket *s) {
+ SocketPort *p;
+
+ /* Flush all incoming traffic, regardless if actual bytes or new connections, so that this socket isn't busy
+ * anymore */
+
+ LIST_FOREACH(port, p, s->ports) {
+ if (p->fd < 0)
+ continue;
+
+ (void) flush_accept(p->fd);
+ (void) flush_fd(p->fd);
+ }
+}
+
static void socket_enter_running(Socket *s, int cfd) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -1891,31 +1990,15 @@ static void socket_enter_running(Socket *s, int cfd) {
assert(s);
- /* We don't take connections anymore if we are supposed to
- * shut down anyway */
+ /* We don't take connections anymore if we are supposed to shut down anyway */
if (unit_stop_pending(UNIT(s))) {
log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled.");
if (cfd >= 0)
cfd = safe_close(cfd);
- else {
- /* Flush all sockets by closing and reopening them */
- socket_close_fds(s);
-
- r = socket_open_fds(s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to listen on sockets: %m");
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- return;
- }
-
- r = socket_watch_fds(s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- }
- }
+ else
+ flush_ports(s);
return;
}
diff --git a/src/core/transaction.c b/src/core/transaction.c
index d5370b2a14..e06a48a2f1 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -597,7 +597,7 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
/* Not invalidating recursively. Avoids triggering
* OnFailure= actions of dependent jobs. Also avoids
* invalidating our iterator. */
- job_finish_and_invalidate(j, JOB_CANCELED, false);
+ job_finish_and_invalidate(j, JOB_CANCELED, false, false);
}
}
diff --git a/src/core/unit.c b/src/core/unit.c
index 04addc1f70..2fff3f2d8b 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -1249,7 +1249,7 @@ int unit_load(Unit *u) {
fclose(u->transient_file);
u->transient_file = NULL;
- u->dropin_mtime = now(CLOCK_REALTIME);
+ u->fragment_mtime = now(CLOCK_REALTIME);
}
if (UNIT_VTABLE(u)->load) {
@@ -1918,12 +1918,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
case JOB_VERIFY_ACTIVE:
if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
+ job_finish_and_invalidate(u->job, JOB_DONE, true, false);
else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
unexpected = true;
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
+ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
}
break;
@@ -1934,12 +1934,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->job->state == JOB_RUNNING) {
if (ns == UNIT_ACTIVE)
- job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true);
+ job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true, false);
else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
unexpected = true;
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
+ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
}
}
@@ -1950,10 +1950,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
case JOB_TRY_RESTART:
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
+ job_finish_and_invalidate(u->job, JOB_DONE, true, false);
else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
unexpected = true;
- job_finish_and_invalidate(u->job, JOB_FAILED, true);
+ job_finish_and_invalidate(u->job, JOB_FAILED, true, false);
}
break;
@@ -2402,9 +2402,11 @@ int unit_set_slice(Unit *u, Unit *slice) {
if (UNIT_DEREF(u->slice) == slice)
return 0;
- if (UNIT_ISSET(u->slice))
+ /* Disallow slice changes if @u is already bound to cgroups */
+ if (UNIT_ISSET(u->slice) && u->cgroup_realized)
return -EBUSY;
+ unit_ref_unset(&u->slice);
unit_ref_set(&u->slice, slice);
return 1;
}
diff --git a/src/core/unit.h b/src/core/unit.h
index f14972728e..08a927962d 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -186,6 +186,7 @@ struct Unit {
/* Counterparts in the cgroup filesystem */
char *cgroup_path;
CGroupMask cgroup_realized_mask;
+ CGroupMask cgroup_enabled_mask;
CGroupMask cgroup_subtree_mask;
CGroupMask cgroup_members_mask;
int cgroup_inotify_wd;
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index 41fc1993d5..999de63900 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -739,15 +739,16 @@ static int process_socket(int fd) {
.msg_iovlen = 1,
};
ssize_t n;
- int l;
+ ssize_t l;
if (!GREEDY_REALLOC(iovec, n_iovec_allocated, n_iovec + 3)) {
r = log_oom();
goto finish;
}
- if (ioctl(fd, FIONREAD, &l) < 0) {
- r = log_error_errno(errno, "FIONREAD failed: %m");
+ l = next_datagram_size_fd(fd);
+ if (l < 0) {
+ r = log_error_errno(l, "Failed to determine datagram size to read: %m");
goto finish;
}
@@ -847,7 +848,7 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd)
if (fd < 0)
return log_error_errno(errno, "Failed to create coredump socket: %m");
- if (connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return log_error_errno(errno, "Failed to connect to coredump service: %m");
for (i = 0; i < n_iovec; i++) {
diff --git a/src/delta/delta.c b/src/delta/delta.c
index b4f0ecff2d..f32744def2 100644
--- a/src/delta/delta.c
+++ b/src/delta/delta.c
@@ -105,7 +105,7 @@ static int notify_override_masked(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight_red(), "[MASKED]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -115,7 +115,7 @@ static int notify_override_equivalent(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight_green(), "[EQUIVALENT]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -125,7 +125,7 @@ static int notify_override_redirected(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight(), "[REDIRECTED]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -135,7 +135,7 @@ static int notify_override_overridden(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight(), "[OVERRIDDEN]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -145,7 +145,7 @@ static int notify_override_extended(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight(), "[EXTENDED]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -247,7 +247,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
return -ENOMEM;
d = p + strlen(toppath) + 1;
- log_debug("Adding at top: %s %s %s", d, draw_special_char(DRAW_ARROW), p);
+ log_debug("Adding at top: %s %s %s", d, special_glyph(ARROW), p);
k = hashmap_put(top, d, p);
if (k >= 0) {
p = strdup(p);
@@ -259,7 +259,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
return k;
}
- log_debug("Adding at bottom: %s %s %s", d, draw_special_char(DRAW_ARROW), p);
+ log_debug("Adding at bottom: %s %s %s", d, special_glyph(ARROW), p);
free(hashmap_remove(bottom, d));
k = hashmap_put(bottom, d, p);
if (k < 0) {
@@ -283,7 +283,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
return -ENOMEM;
log_debug("Adding to drops: %s %s %s %s %s",
- unit, draw_special_char(DRAW_ARROW), basename(p), draw_special_char(DRAW_ARROW), p);
+ unit, special_glyph(ARROW), basename(p), special_glyph(ARROW), p);
k = hashmap_put(h, basename(p), p);
if (k < 0) {
free(p);
@@ -334,7 +334,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
if (!p)
return -ENOMEM;
- log_debug("Adding at top: %s %s %s", basename(p), draw_special_char(DRAW_ARROW), p);
+ log_debug("Adding at top: %s %s %s", basename(p), special_glyph(ARROW), p);
k = hashmap_put(top, basename(p), p);
if (k >= 0) {
p = strdup(p);
@@ -345,7 +345,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
return k;
}
- log_debug("Adding at bottom: %s %s %s", basename(p), draw_special_char(DRAW_ARROW), p);
+ log_debug("Adding at bottom: %s %s %s", basename(p), special_glyph(ARROW), p);
free(hashmap_remove(bottom, basename(p)));
k = hashmap_put(bottom, basename(p), p);
if (k < 0) {
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 435e3805c4..3df72460ef 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -160,7 +160,7 @@ static int prompt_loop(const char *text, char **l, bool (*is_valid)(const char *
_cleanup_free_ char *p = NULL;
unsigned u;
- r = ask_string(&p, "%s %s (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET), text);
+ r = ask_string(&p, "%s %s (empty to skip): ", special_glyph(TRIANGULAR_BULLET), text);
if (r < 0)
return log_error_errno(r, "Failed to query user: %m");
@@ -371,7 +371,7 @@ static int prompt_hostname(void) {
for (;;) {
_cleanup_free_ char *h = NULL;
- r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET));
+ r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", special_glyph(TRIANGULAR_BULLET));
if (r < 0)
return log_error_errno(r, "Failed to query hostname: %m");
@@ -456,8 +456,8 @@ static int prompt_root_password(void) {
print_welcome();
putchar('\n');
- msg1 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter a new root password (empty to skip): ");
- msg2 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter new root password again: ");
+ msg1 = strjoina(special_glyph(TRIANGULAR_BULLET), " Please enter a new root password (empty to skip): ");
+ msg2 = strjoina(special_glyph(TRIANGULAR_BULLET), " Please enter new root password again: ");
for (;;) {
_cleanup_string_free_erase_ char *a = NULL, *b = NULL;
diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
index 6f56066da8..d32e1d923e 100644
--- a/src/fsck/fsck.c
+++ b/src/fsck/fsck.c
@@ -262,7 +262,7 @@ static int fsck_progress_socket(void) {
if (fd < 0)
return log_warning_errno(errno, "socket(): %m");
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = log_full_errno(errno == ECONNREFUSED || errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
errno, "Failed to connect to progress socket %s, ignoring: %m", sa.un.sun_path);
safe_close(fd);
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index 343e3b1817..108522873e 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -489,6 +489,7 @@ static int parse_fstab(bool initrd) {
static int add_sysroot_mount(void) {
_cleanup_free_ char *what = NULL;
const char *opts;
+ int r;
if (isempty(arg_root_what)) {
log_debug("Could not find a root= entry on the kernel command line.");
@@ -508,6 +509,13 @@ static int add_sysroot_mount(void) {
opts = arg_root_options;
log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
+
+ if (is_device_path(what)) {
+ r = generator_write_initrd_root_device_deps(arg_dest, what);
+ if (r < 0)
+ return r;
+ }
+
return add_mount(what,
"/sysroot",
arg_root_fstype,
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index af96adec06..a4938a7c3a 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -956,6 +956,12 @@ static int add_root_mount(void) {
* wait for a root device to show up. A udev rule will create
* the link for us under the right name. */
+ if (in_initrd()) {
+ r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
+ if (r < 0)
+ return 0;
+ }
+
return add_mount(
"root",
"/dev/gpt-auto-root",
diff --git a/src/import/importd.c b/src/import/importd.c
index d2a5867a6e..956a82945c 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -677,7 +677,7 @@ static int manager_new(Manager **ret) {
(void) mkdir_parents_label(sa.un.sun_path, 0755);
(void) unlink(sa.un.sun_path);
- if (bind(m->notify_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
if (setsockopt(m->notify_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c
index f0959b6237..5e8a3e3200 100644
--- a/src/journal/journal-send.c
+++ b/src/journal/journal-send.c
@@ -208,13 +208,13 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
struct iovec *w;
uint64_t *l;
int i, j = 0;
- struct sockaddr_un sa = {
- .sun_family = AF_UNIX,
- .sun_path = "/run/systemd/journal/socket",
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/socket",
};
struct msghdr mh = {
- .msg_name = &sa,
- .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
+ .msg_name = (struct sockaddr*) &sa.sa,
+ .msg_namelen = SOCKADDR_UN_LEN(sa.un),
};
ssize_t k;
bool have_syslog_identifier = false;
@@ -392,7 +392,7 @@ _public_ int sd_journal_perror(const char *message) {
}
_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
- union sockaddr_union sa = {
+ static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
@@ -408,7 +408,7 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
if (fd < 0)
return -errno;
- r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return -errno;
diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c
index a445291a5e..0a1ce205c2 100644
--- a/src/journal/journald-native.c
+++ b/src/journal/journald-native.c
@@ -448,24 +448,24 @@ void server_process_native_file(
}
int server_open_native_socket(Server*s) {
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/socket",
+ };
static const int one = 1;
int r;
assert(s);
if (s->native_fd < 0) {
- union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/socket",
- };
-
s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->native_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
- unlink(sa.un.sun_path);
+ (void) unlink(sa.un.sun_path);
- r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = bind(s->native_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index e14d0ad980..8f82d2a838 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1696,7 +1696,7 @@ static int server_connect_notify(Server *s) {
if (sa.un.sun_path[0] == '@')
sa.un.sun_path[0] = 0;
- r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e));
+ r = connect(s->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "Failed to connect to notify socket: %m");
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index 59352bcb3f..4ad16ee41c 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -700,23 +700,22 @@ fail:
}
int server_open_stdout_socket(Server *s) {
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/stdout",
+ };
int r;
assert(s);
if (s->stdout_fd < 0) {
- union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/stdout",
- };
-
s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->stdout_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
- unlink(sa.un.sun_path);
+ (void) unlink(sa.un.sun_path);
- r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = bind(s->stdout_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c
index 5153fd0cce..0609b4b694 100644
--- a/src/journal/journald-syslog.c
+++ b/src/journal/journald-syslog.c
@@ -52,8 +52,7 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
.msg_iov = (struct iovec *) iovec,
.msg_iovlen = n_iovec,
.msg_name = (struct sockaddr*) &sa.sa,
- .msg_namelen = offsetof(union sockaddr_union, un.sun_path)
- + strlen("/run/systemd/journal/syslog"),
+ .msg_namelen = SOCKADDR_UN_LEN(sa.un),
};
struct cmsghdr *cmsg;
union {
@@ -316,12 +315,12 @@ static void syslog_skip_date(char **buf) {
}
void server_process_syslog_message(
- Server *s,
- const char *buf,
- const struct ucred *ucred,
- const struct timeval *tv,
- const char *label,
- size_t label_len) {
+ Server *s,
+ const char *buf,
+ const struct ucred *ucred,
+ const struct timeval *tv,
+ const char *label,
+ size_t label_len) {
char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)],
syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
@@ -365,14 +364,12 @@ void server_process_syslog_message(
if (identifier) {
syslog_identifier = strjoina("SYSLOG_IDENTIFIER=", identifier);
- if (syslog_identifier)
- IOVEC_SET_STRING(iovec[n++], syslog_identifier);
+ IOVEC_SET_STRING(iovec[n++], syslog_identifier);
}
if (pid) {
syslog_pid = strjoina("SYSLOG_PID=", pid);
- if (syslog_pid)
- IOVEC_SET_STRING(iovec[n++], syslog_pid);
+ IOVEC_SET_STRING(iovec[n++], syslog_pid);
}
message = strjoina("MESSAGE=", buf);
@@ -383,24 +380,24 @@ void server_process_syslog_message(
}
int server_open_syslog_socket(Server *s) {
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/dev-log",
+ };
static const int one = 1;
int r;
assert(s);
if (s->syslog_fd < 0) {
- static const union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/dev-log",
- };
-
s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->syslog_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
- unlink(sa.un.sun_path);
+ (void) unlink(sa.un.sun_path);
- r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = bind(s->syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
@@ -437,6 +434,7 @@ int server_open_syslog_socket(Server *s) {
void server_maybe_warn_forward_syslog_missed(Server *s) {
usec_t n;
+
assert(s);
if (s->n_forward_syslog_missed <= 0)
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 99b3a1d01f..2badcdff58 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -32,6 +32,7 @@
#include "network-internal.h"
#include "parse-util.h"
#include "siphash24.h"
+#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
#include "utf8.h"
@@ -175,58 +176,19 @@ int config_parse_net_condition(const char *unit,
return 0;
}
-int config_parse_ifname(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- char **s = data;
- _cleanup_free_ char *n = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- n = strdup(rvalue);
- if (!n)
- return log_oom();
-
- if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
- return 0;
- }
-
- free(*s);
- if (*n) {
- *s = n;
- n = NULL;
- } else
- *s = NULL;
-
- return 0;
-}
-
-int config_parse_ifnames(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_ifnames(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
char ***sv = data;
- const char *word, *state;
- size_t l;
int r;
assert(filename);
@@ -234,22 +196,27 @@ int config_parse_ifnames(const char *unit,
assert(rvalue);
assert(data);
- FOREACH_WORD(word, l, rvalue, state) {
- char *n;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
- n = strndup(word, l);
- if (!n)
- return log_oom();
+ r = extract_first_word(&rvalue, &word, NULL, 0);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue);
+ return 0;
+ }
+ if (r == 0)
+ break;
- if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
- free(n);
+ if (!ifname_valid(word)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
return 0;
}
- r = strv_consume(sv, n);
+ r = strv_push(sv, word);
if (r < 0)
return log_oom();
+
+ word = NULL;
}
return 0;
@@ -380,28 +347,28 @@ void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
int deserialize_in_addrs(struct in_addr **ret, const char *string) {
_cleanup_free_ struct in_addr *addresses = NULL;
int size = 0;
- const char *word, *state;
- size_t len;
assert(ret);
assert(string);
- FOREACH_WORD(word, len, string, state) {
- _cleanup_free_ char *addr_str = NULL;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
struct in_addr *new_addresses;
int r;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
if (!new_addresses)
return -ENOMEM;
else
addresses = new_addresses;
- addr_str = strndup(word, len);
- if (!addr_str)
- return -ENOMEM;
-
- r = inet_pton(AF_INET, addr_str, &(addresses[size]));
+ r = inet_pton(AF_INET, word, &(addresses[size]));
if (r <= 0)
continue;
@@ -431,28 +398,28 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
_cleanup_free_ struct in6_addr *addresses = NULL;
int size = 0;
- const char *word, *state;
- size_t len;
assert(ret);
assert(string);
- FOREACH_WORD(word, len, string, state) {
- _cleanup_free_ char *addr_str = NULL;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
struct in6_addr *new_addresses;
int r;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
if (!new_addresses)
return -ENOMEM;
else
addresses = new_addresses;
- addr_str = strndup(word, len);
- if (!addr_str)
- return -ENOMEM;
-
- r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
+ r = inet_pton(AF_INET6, word, &(addresses[size]));
if (r <= 0)
continue;
@@ -493,29 +460,29 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
_cleanup_free_ struct sd_dhcp_route *routes = NULL;
size_t size = 0, allocated = 0;
- const char *word, *state;
- size_t len;
assert(ret);
assert(ret_size);
assert(ret_allocated);
assert(string);
- FOREACH_WORD(word, len, string, state) {
- /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
- _cleanup_free_ char* entry = NULL;
+ /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
char *tok, *tok_end;
unsigned n;
int r;
- if (!GREEDY_REALLOC(routes, allocated, size + 1))
- return -ENOMEM;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
- entry = strndup(word, len);
- if (!entry)
+ if (!GREEDY_REALLOC(routes, allocated, size + 1))
return -ENOMEM;
- tok = entry;
+ tok = word;
/* get the subnet */
tok_end = strchr(tok, '/');
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index 72432774d7..5bcd577167 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -50,10 +50,6 @@ int config_parse_hwaddr(const char *unit, const char *filename, unsigned line,
const char *section, unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_ifname(const char *unit, const char *filename, unsigned line,
- const char *section, unsigned section_line, const char *lvalue,
- int ltype, const char *rvalue, void *data, void *userdata);
-
int config_parse_ifnames(const char *unit, const char *filename, unsigned line,
const char *section, unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c
index 5964a01c4f..21a6b20a11 100644
--- a/src/libsystemd/sd-bus/bus-dump.c
+++ b/src/libsystemd/sd-bus/bus-dump.c
@@ -74,7 +74,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
"%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64,
m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
- m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_normal(),
+ m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", special_glyph(TRIANGULAR_BULLET), ansi_normal(),
ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(),
m->header->endian,
m->header->flags,
diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c
index 56bd5863a8..bfe967bfb0 100644
--- a/src/libsystemd/sd-bus/busctl.c
+++ b/src/libsystemd/sd-bus/busctl.c
@@ -249,8 +249,8 @@ static void print_subtree(const char *prefix, const char *path, char **l) {
l++;
}
- vertical = strjoina(prefix, draw_special_char(DRAW_TREE_VERTICAL));
- space = strjoina(prefix, draw_special_char(DRAW_TREE_SPACE));
+ vertical = strjoina(prefix, special_glyph(TREE_VERTICAL));
+ space = strjoina(prefix, special_glyph(TREE_SPACE));
for (;;) {
bool has_more = false;
@@ -271,7 +271,7 @@ static void print_subtree(const char *prefix, const char *path, char **l) {
n++;
}
- printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
+ printf("%s%s%s\n", prefix, special_glyph(has_more ? TREE_BRANCH : TREE_RIGHT), *l);
print_subtree(has_more ? vertical : space, *l, l);
l = n;
@@ -1079,10 +1079,21 @@ static int message_pcap(sd_bus_message *m, FILE *f) {
}
static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
- bool added_something = false;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char **i;
+ uint32_t flags = 0;
int r;
+ /* upgrade connection; it's not used for anything else after this call */
+ r = sd_bus_message_new_method_call(bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(message, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
STRV_FOREACH(i, argv+1) {
_cleanup_free_ char *m = NULL;
@@ -1095,34 +1106,38 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL
if (!m)
return log_oom();
- r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
+ r = sd_bus_message_append_basic(message, 's', m);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
+ return bus_log_create_error(r);
free(m);
m = strjoin("destination='", *i, "'", NULL);
if (!m)
return log_oom();
- r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
+ r = sd_bus_message_append_basic(message, 's', m);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
-
- added_something = true;
+ return bus_log_create_error(r);
}
STRV_FOREACH(i, arg_matches) {
- r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
+ r = sd_bus_message_append_basic(message, 's', *i);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
-
- added_something = true;
+ return bus_log_create_error(r);
}
- if (!added_something) {
- r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
+ r = sd_bus_message_close_container(message);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(message, 'u', &flags);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, message, arg_timeout, &error, NULL);
+ if (r < 0) {
+ log_error("%s", bus_error_message(&error, r));
+ return r;
}
log_info("Monitoring bus message stream.");
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 04da94e7e3..ed5f94e136 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -836,7 +836,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
b->sockaddr.un.sun_family = AF_UNIX;
strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
- b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen("/var/run/dbus/system_bus_socket");
+ b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un);
return 0;
}
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index bd1c7f15ff..4da9dbfd63 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -458,9 +458,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
if (sockaddr.un.sun_path[0] == '@')
sockaddr.un.sun_path[0] = 0;
- msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
- if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
- msghdr.msg_namelen = sizeof(struct sockaddr_un);
+ msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
have_pid = pid != 0 && pid != getpid();
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index a281f99a34..0a84d75e24 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -265,6 +265,42 @@ static int property_get_docked(
return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m));
}
+static int property_get_current_sessions(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
+
+ return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->sessions));
+}
+
+static int property_get_current_inhibitors(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
+
+ return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->inhibitors));
+}
+
static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
@@ -725,6 +761,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
m->seat0->positions[vtnr]->class != SESSION_GREETER)
return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
+ if (hashmap_size(m->sessions) >= m->sessions_max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max);
+
audit_session_from_pid(leader, &audit_id);
if (audit_id > 0) {
/* Keep our session IDs and the audit session IDs in sync */
@@ -2442,6 +2481,9 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
if (r < 0)
return r;
+ if (hashmap_size(m->inhibitors) >= m->inhibitors_max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", m->inhibitors_max);
+
do {
id = mfree(id);
@@ -2512,6 +2554,13 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0),
SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0),
+ SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimeDirectorySize", "t", bus_property_get_size, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_current_inhibitors, 0, 0),
+ SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_current_sessions, 0, 0),
+ SD_BUS_PROPERTY("UserTasksMax", "t", NULL, offsetof(Manager, user_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
index 8552c464cc..6bd08adc05 100644
--- a/src/login/logind-gperf.gperf
+++ b/src/login/logind-gperf.gperf
@@ -34,4 +34,6 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag
Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec)
Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size)
Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc)
+Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max)
+Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max)
Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max)
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index a0e3ba2b7c..6c78e0dddc 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -317,7 +317,7 @@ int inhibitor_create_fifo(Inhibitor *i) {
if (r < 0)
return r;
- r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
+ r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10);
if (r < 0)
return r;
}
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
index 3cee10d009..f934a5326a 100644
--- a/src/login/logind-seat-dbus.c
+++ b/src/login/logind-seat-dbus.c
@@ -306,7 +306,7 @@ const sd_bus_vtable seat_vtable[] = {
SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index 0f8862c0d9..22dea5db1f 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -180,6 +180,24 @@ static int property_get_idle_since_hint(
return sd_bus_message_append(reply, "t", u);
}
+static int property_get_locked_hint(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Session *s = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(s);
+
+ return sd_bus_message_append(reply, "b", session_get_locked_hint(s) > 0);
+}
+
int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
int r;
@@ -279,6 +297,35 @@ static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_
return sd_bus_reply_method_return(message, NULL);
}
+static int method_set_locked_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+ Session *s = userdata;
+ uid_t uid;
+ int r, b;
+
+ assert(message);
+ assert(s);
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_get_euid(creds, &uid);
+ if (r < 0)
+ return r;
+
+ if (uid != 0 && uid != s->user->uid)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint");
+
+ session_set_locked_hint(s, b);
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
const char *swho;
@@ -487,12 +534,14 @@ const sd_bus_vtable session_vtable[] = {
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_METHOD("Terminate", NULL, NULL, bus_session_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Activate", NULL, NULL, bus_session_method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Lock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unlock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLockedHint", "b", NULL, method_set_locked_hint, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Kill", "si", NULL, bus_session_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index a8b1d5943d..1e0666884a 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -852,6 +852,23 @@ void session_set_idle_hint(Session *s, bool b) {
manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
}
+int session_get_locked_hint(Session *s) {
+ assert(s);
+
+ return s->locked_hint;
+}
+
+void session_set_locked_hint(Session *s, bool b) {
+ assert(s);
+
+ if (s->locked_hint == b)
+ return;
+
+ s->locked_hint = b;
+
+ session_send_changed(s, "LockedHint", NULL);
+}
+
static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
Session *s = userdata;
@@ -897,7 +914,9 @@ int session_create_fifo(Session *s) {
if (r < 0)
return r;
- r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
+ /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
+ * sessions). */
+ r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
if (r < 0)
return r;
}
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index e24b808474..ffb7cd2d41 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -105,6 +105,8 @@ struct Session {
bool idle_hint;
dual_timestamp idle_hint_timestamp;
+ bool locked_hint;
+
bool in_gc_queue:1;
bool started:1;
bool stopping:1;
@@ -132,6 +134,8 @@ int session_activate(Session *s);
bool session_is_active(Session *s);
int session_get_idle_hint(Session *s, dual_timestamp *t);
void session_set_idle_hint(Session *s, bool b);
+int session_get_locked_hint(Session *s);
+void session_set_locked_hint(Session *s, bool b);
int session_create_fifo(Session *s);
int session_start(Session *s);
int session_stop(Session *s, bool force);
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index b73f9ea69e..af6392e025 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -245,7 +245,7 @@ const sd_bus_vtable user_vtable[] = {
SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
- SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
diff --git a/src/login/logind.c b/src/login/logind.c
index a48e2fc61e..caf149cfb7 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -62,7 +62,9 @@ static void manager_reset_config(Manager *m) {
m->idle_action = HANDLE_IGNORE;
m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
- m->user_tasks_max = UINT64_C(12288);
+ m->user_tasks_max = 12288;
+ m->sessions_max = 8192;
+ m->inhibitors_max = 8192;
m->kill_user_processes = KILL_USER_PROCESSES;
@@ -686,7 +688,7 @@ static int manager_connect_bus(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to register name: %m");
- r = sd_bus_attach_event(m->bus, m->event, 0);
+ r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in
index 3c96def45d..32c0844cb6 100644
--- a/src/login/logind.conf.in
+++ b/src/login/logind.conf.in
@@ -32,4 +32,6 @@
#IdleActionSec=30min
#RuntimeDirectorySize=10%
#RemoveIPC=yes
+#InhibitorsMax=8192
+#SessionsMax=8192
#UserTasksMax=12288
diff --git a/src/login/logind.h b/src/login/logind.h
index 6748af3c07..90431eb4b0 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -133,6 +133,8 @@ struct Manager {
size_t runtime_dir_size;
uint64_t user_tasks_max;
+ uint64_t sessions_max;
+ uint64_t inhibitors_max;
};
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device);
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index 1662d4c428..c89e40457e 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -234,6 +234,10 @@
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Session"
+ send_member="SetLockedHint"/>
+
+ <allow send_destination="org.freedesktop.login1"
+ send_interface="org.freedesktop.login1.Session"
send_member="Kill"/>
<allow send_destination="org.freedesktop.login1"
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 40e246bb06..98dc201340 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -150,7 +150,7 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
if (fd < 0)
return -errno;
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
r = getpeercred(fd, &ucred);
diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c
index bd603e297d..29785e2f11 100644
--- a/src/login/sysfs-show.c
+++ b/src/login/sysfs-show.c
@@ -110,7 +110,7 @@ static int show_sysfs_one(
if (!k)
return -ENOMEM;
- printf("%s%s%s\n", prefix, draw_special_char(lookahead ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), k);
+ printf("%s%s%s\n", prefix, special_glyph(lookahead ? TREE_BRANCH : TREE_RIGHT), k);
if (asprintf(&l,
"%s%s:%s%s%s%s",
@@ -124,13 +124,13 @@ static int show_sysfs_one(
if (!k)
return -ENOMEM;
- printf("%s%s%s\n", prefix, lookahead ? draw_special_char(DRAW_TREE_VERTICAL) : " ", k);
+ printf("%s%s%s\n", prefix, lookahead ? special_glyph(TREE_VERTICAL) : " ", k);
*item = next;
if (*item) {
_cleanup_free_ char *p = NULL;
- p = strappend(prefix, lookahead ? draw_special_char(DRAW_TREE_VERTICAL) : " ");
+ p = strappend(prefix, lookahead ? special_glyph(TREE_VERTICAL) : " ");
if (!p)
return -ENOMEM;
@@ -183,7 +183,7 @@ int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) {
if (first)
show_sysfs_one(udev, seat, &first, "/", prefix, n_columns);
else
- printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), "(none)");
+ printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), "(none)");
return r;
}
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index b22a0f648a..d2df9b7560 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -750,7 +750,7 @@ static int link_status_one(
(void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
(void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
- printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, info->ifindex, info->name);
+ printf("%s%s%s %i: %s\n", on_color_operational, special_glyph(BLACK_CIRCLE), off_color_operational, info->ifindex, info->name);
printf(" Link File: %s\n"
" Network File: %s\n"
@@ -818,7 +818,7 @@ static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
printf("%s%s%s State: %s%s%s\n",
- on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
+ on_color_operational, special_glyph(BLACK_CIRCLE), off_color_operational,
on_color_operational, strna(operational_state), off_color_operational);
(void) dump_addresses(rtnl, " Address: ", 0);
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 8b52a1f742..4eb0d927a6 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -27,6 +27,7 @@
#include "networkd.h"
#include "parse-util.h"
#include "set.h"
+#include "socket-util.h"
#include "string-util.h"
#include "utf8.h"
#include "util.h"
@@ -726,7 +727,8 @@ int config_parse_address(const char *unit,
return 0;
}
-int config_parse_label(const char *unit,
+int config_parse_label(
+ const char *unit,
const char *filename,
unsigned line,
const char *section,
@@ -736,9 +738,9 @@ int config_parse_label(const char *unit,
const char *rvalue,
void *data,
void *userdata) {
- Network *network = userdata;
+
_cleanup_address_free_ Address *n = NULL;
- char *label;
+ Network *network = userdata;
int r;
assert(filename);
@@ -751,23 +753,14 @@ int config_parse_label(const char *unit,
if (r < 0)
return r;
- label = strdup(rvalue);
- if (!label)
- return log_oom();
-
- if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
- free(label);
+ if (!ifname_valid(rvalue)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not valid or too long, ignoring assignment: %s", rvalue);
return 0;
}
- free(n->label);
- if (*label)
- n->label = label;
- else {
- free(label);
- n->label = NULL;
- }
+ r = free_and_strdup(&n->label, rvalue);
+ if (r < 0)
+ return log_oom();
n = NULL;
diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c
index 6072c1e2de..b67a1f6d09 100644
--- a/src/network/networkd-conf.c
+++ b/src/network/networkd-conf.c
@@ -70,7 +70,7 @@ int config_parse_duid_rawdata(
for (;;) {
int n1, n2, len, r;
uint32_t byte;
- char *cbyte;
+ _cleanup_free_ char *cbyte = NULL;
r = extract_first_word(&rvalue, &cbyte, ":", 0);
if (r < 0) {
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index c646af1f1a..4e3f62cf51 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -131,7 +131,7 @@ static bool link_lldp_rx_enabled(Link *link) {
return link->network->lldp_mode != LLDP_MODE_NO;
}
-static bool link_lldp_tx_enabled(Link *link) {
+static bool link_lldp_emit_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
@@ -143,7 +143,7 @@ static bool link_lldp_tx_enabled(Link *link) {
if (!link->network)
return false;
- return link->network->lldp_emit;
+ return link->network->lldp_emit != LLDP_EMIT_NO;
}
static bool link_ipv4_forward_enabled(Link *link) {
@@ -491,7 +491,7 @@ static void link_free(Link *link) {
sd_dhcp_client_unref(link->dhcp_client);
sd_dhcp_lease_unref(link->dhcp_lease);
- link_lldp_tx_stop(link);
+ link_lldp_emit_stop(link);
free(link->lease_file);
@@ -618,7 +618,7 @@ static int link_stop_clients(Link *link) {
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
}
- link_lldp_tx_stop(link);
+ link_lldp_emit_stop(link);
return r;
}
@@ -1411,12 +1411,12 @@ static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n
(void) link_lldp_save(link);
- if (link_lldp_tx_enabled(link) && event == SD_LLDP_EVENT_ADDED) {
+ if (link_lldp_emit_enabled(link) && event == SD_LLDP_EVENT_ADDED) {
/* If we received information about a new neighbor, restart the LLDP "fast" logic */
log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission.");
- r = link_lldp_tx_start(link);
+ r = link_lldp_emit_start(link);
if (r < 0)
log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m");
}
@@ -1501,8 +1501,8 @@ static int link_acquire_conf(Link *link) {
return r;
}
- if (link_lldp_tx_enabled(link)) {
- r = link_lldp_tx_start(link);
+ if (link_lldp_emit_enabled(link)) {
+ r = link_lldp_emit_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
}
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 86139be557..14c4a02c7e 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -121,7 +121,7 @@ typedef struct Link {
/* This is about LLDP transmission */
unsigned lldp_tx_fast; /* The LLDP txFast counter (See 802.1ab-2009, section 9.2.5.18) */
- sd_event_source *lldp_tx_event_source;
+ sd_event_source *lldp_emit_event_source;
Hashmap *bound_by_links;
Hashmap *bound_to_links;
diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c
index 03b694c3f1..3aa768388b 100644
--- a/src/network/networkd-lldp-tx.c
+++ b/src/network/networkd-lldp-tx.c
@@ -25,16 +25,14 @@
#include "fd-util.h"
#include "fileio.h"
#include "hostname-util.h"
+#include "networkd-lldp-tx.h"
+#include "networkd.h"
+#include "parse-util.h"
#include "random-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "unaligned.h"
-#include "networkd.h"
-#include "networkd-lldp-tx.h"
-
-#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
-
/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
#define LLDP_TX_FAST_INIT 4U
@@ -50,6 +48,12 @@
/* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */
#define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
+static const struct ether_addr lldp_multicast_addr[_LLDP_EMIT_MAX] = {
+ [LLDP_EMIT_NEAREST_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }},
+ [LLDP_EMIT_NON_TPMR_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }},
+ [LLDP_EMIT_CUSTOMER_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }},
+};
+
static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) {
assert(p);
@@ -66,6 +70,7 @@ static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) {
}
static int lldp_make_packet(
+ LLDPEmit mode,
const struct ether_addr *hwaddr,
const char *machine_id,
const char *ifname,
@@ -84,6 +89,8 @@ static int lldp_make_packet(
size_t l;
int r;
+ assert(mode > LLDP_EMIT_NO);
+ assert(mode < _LLDP_EMIT_MAX);
assert(hwaddr);
assert(machine_id);
assert(ifname);
@@ -132,7 +139,7 @@ static int lldp_make_packet(
h = (struct ether_header*) packet;
h->ether_type = htobe16(ETHERTYPE_LLDP);
- memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN);
+ memcpy(h->ether_dhost, lldp_multicast_addr + mode, ETH_ALEN);
memcpy(h->ether_shost, hwaddr, ETH_ALEN);
p = (uint8_t*) packet + sizeof(struct ether_header);
@@ -197,22 +204,28 @@ static int lldp_make_packet(
return 0;
}
-static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) {
+static int lldp_send_packet(
+ int ifindex,
+ const struct ether_addr *address,
+ const void *packet,
+ size_t packet_size) {
union sockaddr_union sa = {
.ll.sll_family = AF_PACKET,
.ll.sll_protocol = htobe16(ETHERTYPE_LLDP),
.ll.sll_ifindex = ifindex,
.ll.sll_halen = ETH_ALEN,
- .ll.sll_addr = LLDP_MULTICAST_ADDR,
};
_cleanup_close_ int fd = -1;
ssize_t l;
assert(ifindex > 0);
+ assert(address);
assert(packet || packet_size <= 0);
+ memcpy(sa.ll.sll_addr, address, ETH_ALEN);
+
fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW);
if (fd < 0)
return -errno;
@@ -237,6 +250,13 @@ static int link_send_lldp(Link *link) {
usec_t ttl;
int r;
+ assert(link);
+
+ if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO)
+ return 0;
+
+ assert(link->network->lldp_emit < _LLDP_EMIT_MAX);
+
r = sd_id128_get_machine(&machine_id);
if (r < 0)
return r;
@@ -251,7 +271,8 @@ static int link_send_lldp(Link *link) {
SD_LLDP_SYSTEM_CAPABILITIES_ROUTER :
SD_LLDP_SYSTEM_CAPABILITIES_STATION;
- r = lldp_make_packet(&link->mac,
+ r = lldp_make_packet(link->network->lldp_emit,
+ &link->mac,
sd_id128_to_string(machine_id, machine_id_string),
link->ifname,
(uint16_t) ttl,
@@ -264,7 +285,7 @@ static int link_send_lldp(Link *link) {
if (r < 0)
return r;
- return lldp_send_packet(link->ifindex, packet, packet_size);
+ return lldp_send_packet(link->ifindex, lldp_multicast_addr + link->network->lldp_emit, packet, packet_size);
}
static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
@@ -300,12 +321,17 @@ static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
return 0;
}
-int link_lldp_tx_start(Link *link) {
+int link_lldp_emit_start(Link *link) {
usec_t next;
int r;
assert(link);
+ if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) {
+ link_lldp_emit_stop(link);
+ return 0;
+ }
+
/* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */
link->lldp_tx_fast = LLDP_TX_FAST_INIT;
@@ -313,22 +339,22 @@ int link_lldp_tx_start(Link *link) {
next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC),
(usec_t) random_u64() % LLDP_JITTER_USEC);
- if (link->lldp_tx_event_source) {
+ if (link->lldp_emit_event_source) {
usec_t old;
/* Lower the timeout, maybe */
- r = sd_event_source_get_time(link->lldp_tx_event_source, &old);
+ r = sd_event_source_get_time(link->lldp_emit_event_source, &old);
if (r < 0)
return r;
if (old <= next)
return 0;
- return sd_event_source_set_time(link->lldp_tx_event_source, next);
+ return sd_event_source_set_time(link->lldp_emit_event_source, next);
} else {
r = sd_event_add_time(
link->manager->event,
- &link->lldp_tx_event_source,
+ &link->lldp_emit_event_source,
clock_boottime_or_monotonic(),
next,
0,
@@ -337,14 +363,54 @@ int link_lldp_tx_start(Link *link) {
if (r < 0)
return r;
- (void) sd_event_source_set_description(link->lldp_tx_event_source, "lldp-tx");
+ (void) sd_event_source_set_description(link->lldp_emit_event_source, "lldp-tx");
}
return 0;
}
-void link_lldp_tx_stop(Link *link) {
+void link_lldp_emit_stop(Link *link) {
assert(link);
- link->lldp_tx_event_source = sd_event_source_unref(link->lldp_tx_event_source);
+ link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source);
+}
+
+int config_parse_lldp_emit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ LLDPEmit *emit = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue))
+ *emit = LLDP_EMIT_NO;
+ else if (streq(rvalue, "nearest-bridge"))
+ *emit = LLDP_EMIT_NEAREST_BRIDGE;
+ else if (streq(rvalue, "non-tpmr-bridge"))
+ *emit = LLDP_EMIT_NON_TPMR_BRIDGE;
+ else if (streq(rvalue, "customer-bridge"))
+ *emit = LLDP_EMIT_CUSTOMER_BRIDGE;
+ else {
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse LLDP emission setting, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ *emit = r ? LLDP_EMIT_NEAREST_BRIDGE : LLDP_EMIT_NO;
+ }
+
+ return 0;
}
diff --git a/src/network/networkd-lldp-tx.h b/src/network/networkd-lldp-tx.h
index 8c7f403005..4680c9d950 100644
--- a/src/network/networkd-lldp-tx.h
+++ b/src/network/networkd-lldp-tx.h
@@ -21,5 +21,15 @@
#include "networkd-link.h"
-int link_lldp_tx_start(Link *link);
-void link_lldp_tx_stop(Link *link);
+typedef enum LLDPEmit {
+ LLDP_EMIT_NO,
+ LLDP_EMIT_NEAREST_BRIDGE,
+ LLDP_EMIT_NON_TPMR_BRIDGE,
+ LLDP_EMIT_CUSTOMER_BRIDGE,
+ _LLDP_EMIT_MAX,
+} LLDPEmit;
+
+int link_lldp_emit_start(Link *link);
+void link_lldp_emit_stop(Link *link);
+
+int config_parse_lldp_emit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index 3e44dd7960..4cfd00413f 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -96,6 +96,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_QUERIER attribute: %m");
}
+ if (b->mcast_snooping >= 0) {
+ r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_SNOOPING, b->mcast_snooping);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_SNOOPING attribute: %m");
+ }
+
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
@@ -121,6 +127,7 @@ static void bridge_init(NetDev *n) {
assert(b);
b->mcast_querier = -1;
+ b->mcast_snooping = -1;
}
const NetDevVTable bridge_vtable = {
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index b921439f02..f2ae21fc50 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -25,6 +25,7 @@ typedef struct Bridge {
NetDev meta;
int mcast_querier;
+ int mcast_snooping;
usec_t forward_delay;
usec_t hello_time;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 1ebd0fdf20..ba04bb0165 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -99,3 +99,4 @@ Bridge.HelloTimeSec, config_parse_sec, 0,
Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age)
Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay)
Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier)
+Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping)
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index d7d014f05d..851a36290c 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -656,7 +656,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
if (!netdev->filename)
return log_oom();
- if (!netdev->mac) {
+ if (!netdev->mac && netdev->kind != NETDEV_KIND_VLAN) {
r = netdev_get_mac(netdev->ifname, &netdev->mac);
if (r < 0)
return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 51e750b299..4425ee4e2f 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -27,7 +27,6 @@ Match.KernelCommandLine, config_parse_net_condition,
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)
-Link.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
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)
@@ -43,7 +42,7 @@ Network.LinkLocalAddressing, config_parse_address_family_boolean,
Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode)
-Network.EmitLLDP, config_parse_bool, 0, offsetof(Network, lldp_emit)
+Network.EmitLLDP, config_parse_lldp_emit, 0, offsetof(Network, lldp_emit)
Network.Address, config_parse_address, 0, 0
Network.Gateway, config_parse_gateway, 0, 0
Network.Domains, config_parse_domains, 0, 0
@@ -89,6 +88,7 @@ DHCP.DUIDType, config_parse_duid_type,
DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
+DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns)
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index ff2414efdd..4cd0fa4ab8 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -29,6 +29,7 @@
#include "networkd-address.h"
#include "networkd-fdb.h"
+#include "networkd-lldp-tx.h"
#include "networkd-netdev.h"
#include "networkd-route.h"
#include "networkd-util.h"
@@ -161,7 +162,7 @@ struct Network {
DUID duid;
LLDPMode lldp_mode; /* LLDP reception */
- bool lldp_emit; /* LLDP transmission */
+ LLDPEmit lldp_emit; /* LLDP transmission */
LIST_HEAD(Address, static_addresses);
LIST_HEAD(Route, static_routes);
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index 01094b20bd..43f37266d8 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -512,7 +512,7 @@ int route_configure(Route *route, Link *link,
if (r < 0)
return log_error_errno(r, "Could not set route table: %m");
- /* Table attribute to allow allow more than 256. */
+ /* Table attribute to allow more than 256. */
r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
if (r < 0)
return log_error_errno(r, "Could not append RTA_TABLE attribute: %m");
diff --git a/src/network/networkd.h b/src/network/networkd.h
index 26d9e7d6e0..ab512f0d08 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -41,7 +41,6 @@
#include "networkd-netdev-tuntap.h"
#include "networkd-netdev-veth.h"
#include "networkd-netdev-vlan.h"
-#include "networkd-netdev-vlan.h"
#include "networkd-netdev-vxlan.h"
#include "networkd-network.h"
#include "networkd-util.h"
diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c
index 8a62a2a567..9bd30b82c6 100644
--- a/src/network/test-networkd-conf.c
+++ b/src/network/test-networkd-conf.c
@@ -47,10 +47,12 @@ static void test_config_parse_duid_type(void) {
static void test_config_parse_duid_rawdata_one(const char *rvalue, int ret, const DUID* expected) {
DUID actual = {};
int r;
+ _cleanup_free_ char *d = NULL;
r = config_parse_duid_rawdata("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL);
+ d = hexmem(actual.raw_data, actual.raw_data_len);
log_info_errno(r, "\"%s\" → \"%s\" (%m)",
- rvalue, strnull(hexmem(actual.raw_data, actual.raw_data_len)));
+ rvalue, strnull(d));
assert_se(r == ret);
if (expected) {
assert_se(actual.raw_data_len == expected->raw_data_len);
diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf
index 34e1310e29..2b5d452662 100644
--- a/src/nspawn/nspawn-gperf.gperf
+++ b/src/nspawn/nspawn-gperf.gperf
@@ -39,5 +39,6 @@ Network.MACVLAN, config_parse_strv, 0, offsetof(Settings,
Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan)
Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth)
Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0
-Network.Bridge, config_parse_string, 0, offsetof(Settings, network_bridge)
+Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge)
+Network.Zone, config_parse_network_zone, 0, 0
Network.Port, config_parse_expose_port, 0, 0
diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c
index f2b7e4dd79..8da47a2ca6 100644
--- a/src/nspawn/nspawn-network.c
+++ b/src/nspawn/nspawn-network.c
@@ -26,9 +26,12 @@
#include "alloc-util.h"
#include "ether-addr-util.h"
+#include "lockfile-util.h"
#include "netlink-util.h"
#include "nspawn-network.h"
#include "siphash24.h"
+#include "socket-util.h"
+#include "stat-util.h"
#include "string-util.h"
#include "udev-util.h"
#include "util.h"
@@ -39,6 +42,30 @@
#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
+static int remove_one_link(sd_netlink *rtnl, const char *name) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ if (isempty(name))
+ return 0;
+
+ r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate netlink message: %m");
+
+ r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink interface name: %m");
+
+ r = sd_netlink_call(rtnl, m, 0, NULL);
+ if (r == -ENODEV) /* Already gone */
+ return 0;
+ if (r < 0)
+ return log_error_errno(r, "Failed to remove interface %s: %m", name);
+
+ return 1;
+}
+
static int generate_mac(
const char *machine_name,
struct ether_addr *mac,
@@ -238,45 +265,149 @@ int setup_veth_extra(
return 0;
}
-int setup_bridge(const char *veth_name, const char *bridge_name) {
+static int join_bridge(sd_netlink *rtnl, const char *veth_name, const char *bridge_name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
int r, bridge_ifi;
+ assert(rtnl);
assert(veth_name);
assert(bridge_name);
bridge_ifi = (int) if_nametoindex(bridge_name);
if (bridge_ifi <= 0)
- return log_error_errno(errno, "Failed to resolve interface %s: %m", bridge_name);
-
- r = sd_netlink_open(&rtnl);
- if (r < 0)
- return log_error_errno(r, "Failed to connect to netlink: %m");
+ return -errno;
r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
if (r < 0)
- return log_error_errno(r, "Failed to allocate netlink message: %m");
+ return r;
r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
if (r < 0)
- return log_error_errno(r, "Failed to set IFF_UP flag: %m");
+ return r;
r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
if (r < 0)
- return log_error_errno(r, "Failed to add netlink interface name field: %m");
+ return r;
r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi);
if (r < 0)
- return log_error_errno(r, "Failed to add netlink master field: %m");
+ return r;
r = sd_netlink_call(rtnl, m, 0, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to add veth interface to bridge: %m");
+ return r;
return bridge_ifi;
}
+static int create_bridge(sd_netlink *rtnl, const char *bridge_name) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, IFLA_IFNAME, bridge_name);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "bridge");
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(rtnl, m, 0, NULL);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int setup_bridge(const char *veth_name, const char *bridge_name, bool create) {
+ _cleanup_release_lock_file_ LockFile bridge_lock = LOCK_FILE_INIT;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ int r, bridge_ifi;
+ unsigned n = 0;
+
+ assert(veth_name);
+ assert(bridge_name);
+
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
+
+ if (create) {
+ /* We take a system-wide lock here, so that we can safely check whether there's still a member in the
+ * bridge before removing it, without risking interferance from other nspawn instances. */
+
+ r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
+ if (r < 0)
+ return log_error_errno(r, "Failed to take network zone lock: %m");
+ }
+
+ for (;;) {
+ bridge_ifi = join_bridge(rtnl, veth_name, bridge_name);
+ if (bridge_ifi >= 0)
+ return bridge_ifi;
+ if (bridge_ifi != -ENODEV || !create || n > 10)
+ return log_error_errno(bridge_ifi, "Failed to add interface %s to bridge %s: %m", veth_name, bridge_name);
+
+ /* Count attempts, so that we don't enter an endless loop here. */
+ n++;
+
+ /* The bridge doesn't exist yet. Let's create it */
+ r = create_bridge(rtnl, bridge_name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bridge interface %s: %m", bridge_name);
+
+ /* Try again, now that the bridge exists */
+ }
+}
+
+int remove_bridge(const char *bridge_name) {
+ _cleanup_release_lock_file_ LockFile bridge_lock = LOCK_FILE_INIT;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ const char *path;
+ int r;
+
+ /* Removes the specified bridge, but only if it is currently empty */
+
+ if (isempty(bridge_name))
+ return 0;
+
+ r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
+ if (r < 0)
+ return log_error_errno(r, "Failed to take network zone lock: %m");
+
+ path = strjoina("/sys/class/net/", bridge_name, "/brif");
+
+ r = dir_is_empty(path);
+ if (r == -ENOENT) /* Already gone? */
+ return 0;
+ if (r < 0)
+ return log_error_errno(r, "Can't detect if bridge %s is empty: %m", bridge_name);
+ if (r == 0) /* Still populated, leave it around */
+ return 0;
+
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
+
+ return remove_one_link(rtnl, bridge_name);
+}
+
static int parse_interface(struct udev *udev, const char *name) {
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
char ifi_str[2 + DECIMAL_STR_MAX(int)];
@@ -515,13 +646,13 @@ int veth_extra_parse(char ***l, const char *p) {
r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
- if (r == 0 || isempty(a))
+ if (r == 0 || !ifname_valid(a))
return -EINVAL;
r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
- if (r == 0 || isempty(b)) {
+ if (r == 0 || !ifname_valid(b)) {
free(b);
b = strdup(a);
if (!b)
@@ -539,30 +670,6 @@ int veth_extra_parse(char ***l, const char *p) {
return 0;
}
-static int remove_one_veth_link(sd_netlink *rtnl, const char *name) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- int r;
-
- if (isempty(name))
- return 0;
-
- r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to allocate netlink message: %m");
-
- r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
- if (r < 0)
- return log_error_errno(r, "Failed to add netlink interface name: %m");
-
- r = sd_netlink_call(rtnl, m, 0, NULL);
- if (r == -ENODEV) /* Already gone */
- return 0;
- if (r < 0)
- return log_error_errno(r, "Failed to remove veth interface %s: %m", name);
-
- return 1;
-}
-
int remove_veth_links(const char *primary, char **pairs) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
char **a, **b;
@@ -578,10 +685,10 @@ int remove_veth_links(const char *primary, char **pairs) {
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
- remove_one_veth_link(rtnl, primary);
+ remove_one_link(rtnl, primary);
STRV_FOREACH_PAIR(a, b, pairs)
- remove_one_veth_link(rtnl, *a);
+ remove_one_link(rtnl, *a);
return 0;
}
diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h
index c5036ab470..3d8861e1e5 100644
--- a/src/nspawn/nspawn-network.h
+++ b/src/nspawn/nspawn-network.h
@@ -26,7 +26,8 @@
int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge);
int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs);
-int setup_bridge(const char *veth_name, const char *bridge_name);
+int setup_bridge(const char *veth_name, const char *bridge_name, bool create);
+int remove_bridge(const char *bridge_name);
int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces);
int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces);
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index b98a79fd09..5f1522cfb6 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -24,10 +24,11 @@
#include "nspawn-settings.h"
#include "parse-util.h"
#include "process-util.h"
+#include "socket-util.h"
+#include "string-util.h"
#include "strv.h"
#include "user-util.h"
#include "util.h"
-#include "string-util.h"
int settings_load(FILE *f, const char *path, Settings **ret) {
_cleanup_(settings_freep) Settings *s = NULL;
@@ -96,6 +97,7 @@ Settings* settings_free(Settings *s) {
strv_free(s->network_ipvlan);
strv_free(s->network_veth_extra);
free(s->network_bridge);
+ free(s->network_zone);
expose_port_free_all(s->expose_ports);
custom_mount_free_all(s->custom_mounts, s->n_custom_mounts);
@@ -111,6 +113,7 @@ bool settings_private_network(Settings *s) {
s->private_network > 0 ||
s->network_veth > 0 ||
s->network_bridge ||
+ s->network_zone ||
s->network_interfaces ||
s->network_macvlan ||
s->network_ipvlan ||
@@ -122,7 +125,8 @@ bool settings_network_veth(Settings *s) {
return
s->network_veth > 0 ||
- s->network_bridge;
+ s->network_bridge ||
+ s->network_zone;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
@@ -319,6 +323,38 @@ int config_parse_veth_extra(
return 0;
}
+int config_parse_network_zone(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Settings *settings = data;
+ _cleanup_free_ char *j = NULL;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ j = strappend("vz-", rvalue);
+ if (!ifname_valid(j)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid network zone name %s, ignoring: %m", rvalue);
+ return 0;
+ }
+
+ free(settings->network_zone);
+ settings->network_zone = j;
+ j = NULL;
+
+ return 0;
+}
+
int config_parse_boot(
const char *unit,
const char *filename,
diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h
index e12e91b886..1c47e37912 100644
--- a/src/nspawn/nspawn-settings.h
+++ b/src/nspawn/nspawn-settings.h
@@ -85,6 +85,7 @@ typedef struct Settings {
int private_network;
int network_veth;
char *network_bridge;
+ char *network_zone;
char **network_interfaces;
char **network_macvlan;
char **network_ipvlan;
@@ -109,6 +110,7 @@ int config_parse_volatile_mode(const char *unit, const char *filename, unsigned
int config_parse_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_tmpfs(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_veth_extra(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_network_zone(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_boot(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_private_users(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 3fc6cc955c..8ec058431b 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -176,6 +176,7 @@ static char **arg_network_ipvlan = NULL;
static bool arg_network_veth = false;
static char **arg_network_veth_extra = NULL;
static char *arg_network_bridge = NULL;
+static char *arg_network_zone = NULL;
static unsigned long arg_personality = PERSONALITY_INVALID;
static char *arg_image = NULL;
static VolatileMode arg_volatile_mode = VOLATILE_NO;
@@ -234,6 +235,8 @@ static void help(void) {
" Add a virtual Ethernet connection between host\n"
" and container and add it to an existing bridge on\n"
" the host\n"
+ " --network-zone=NAME Add a virtual Ethernet connection to the container,\n"
+ " and add it to an automatically managed bridge interface\n"
" -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n"
" Expose a container IP port on the host\n"
" -Z --selinux-context=SECLABEL\n"
@@ -357,6 +360,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NETWORK_MACVLAN,
ARG_NETWORK_IPVLAN,
ARG_NETWORK_BRIDGE,
+ ARG_NETWORK_ZONE,
ARG_NETWORK_VETH_EXTRA,
ARG_PERSONALITY,
ARG_VOLATILE,
@@ -404,6 +408,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "network-veth", no_argument, NULL, 'n' },
{ "network-veth-extra", required_argument, NULL, ARG_NETWORK_VETH_EXTRA},
{ "network-bridge", required_argument, NULL, ARG_NETWORK_BRIDGE },
+ { "network-zone", required_argument, NULL, ARG_NETWORK_ZONE },
{ "personality", required_argument, NULL, ARG_PERSONALITY },
{ "image", required_argument, NULL, 'i' },
{ "volatile", optional_argument, NULL, ARG_VOLATILE },
@@ -466,7 +471,35 @@ static int parse_argv(int argc, char *argv[]) {
arg_settings_mask |= SETTING_USER;
break;
+ case ARG_NETWORK_ZONE: {
+ char *j;
+
+ j = strappend("vz-", optarg);
+ if (!j)
+ return log_oom();
+
+ if (!ifname_valid(j)) {
+ log_error("Network zone name not valid: %s", j);
+ free(j);
+ return -EINVAL;
+ }
+
+ free(arg_network_zone);
+ arg_network_zone = j;
+
+ arg_network_veth = true;
+ arg_private_network = true;
+ arg_settings_mask |= SETTING_NETWORK;
+ break;
+ }
+
case ARG_NETWORK_BRIDGE:
+
+ if (!ifname_valid(optarg)) {
+ log_error("Bridge interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
r = free_and_strdup(&arg_network_bridge, optarg);
if (r < 0)
return log_oom();
@@ -489,6 +522,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_NETWORK_INTERFACE:
+
+ if (!ifname_valid(optarg)) {
+ log_error("Network interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
if (strv_extend(&arg_network_interfaces, optarg) < 0)
return log_oom();
@@ -497,6 +536,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_NETWORK_MACVLAN:
+
+ if (!ifname_valid(optarg)) {
+ log_error("MACVLAN network interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
if (strv_extend(&arg_network_macvlan, optarg) < 0)
return log_oom();
@@ -505,6 +550,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_NETWORK_IPVLAN:
+
+ if (!ifname_valid(optarg)) {
+ log_error("IPVLAN network interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
if (strv_extend(&arg_network_ipvlan, optarg) < 0)
return log_oom();
@@ -1003,6 +1054,11 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (arg_network_bridge && arg_network_zone) {
+ log_error("--network-bridge= and --network-zone= may not be combined.");
+ return -EINVAL;
+ }
+
if (argc > optind) {
arg_parameters = strv_copy(argv + optind);
if (!arg_parameters)
@@ -1657,7 +1713,6 @@ static int setup_seccomp(void) {
}
}
-
/*
Audit is broken in containers, much of the userspace audit
hookup will fail if running inside a container. We don't
@@ -3271,6 +3326,7 @@ static int load_settings(void) {
(settings->private_network >= 0 ||
settings->network_veth >= 0 ||
settings->network_bridge ||
+ settings->network_zone ||
settings->network_interfaces ||
settings->network_macvlan ||
settings->network_ipvlan ||
@@ -3301,6 +3357,10 @@ static int load_settings(void) {
free(arg_network_bridge);
arg_network_bridge = settings->network_bridge;
settings->network_bridge = NULL;
+
+ free(arg_network_zone);
+ arg_network_zone = settings->network_zone;
+ settings->network_zone = NULL;
}
}
@@ -3346,7 +3406,7 @@ int main(int argc, char *argv[]) {
int ret = EXIT_SUCCESS;
union in_addr_union exposed = {};
_cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
- bool interactive;
+ bool interactive, veth_created = false;
log_parse_environment();
log_open();
@@ -3800,14 +3860,23 @@ int main(int argc, char *argv[]) {
goto finish;
if (arg_network_veth) {
- r = setup_veth(arg_machine, pid, veth_name, !!arg_network_bridge);
+ r = setup_veth(arg_machine, pid, veth_name,
+ arg_network_bridge || arg_network_zone);
if (r < 0)
goto finish;
else if (r > 0)
ifi = r;
if (arg_network_bridge) {
- r = setup_bridge(veth_name, arg_network_bridge);
+ /* Add the interface to a bridge */
+ r = setup_bridge(veth_name, arg_network_bridge, false);
+ if (r < 0)
+ goto finish;
+ if (r > 0)
+ ifi = r;
+ } else if (arg_network_zone) {
+ /* Add the interface to a bridge, possibly creating it */
+ r = setup_bridge(veth_name, arg_network_zone, true);
if (r < 0)
goto finish;
if (r > 0)
@@ -3819,6 +3888,12 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
+ /* We created the primary and extra veth links now; let's remember this, so that we know to
+ remove them later on. Note that we don't bother with removing veth links that were created
+ here when their setup failed half-way, because in that case the kernel should be able to
+ remove them on its own, since they cannot be referenced by anything yet. */
+ veth_created = true;
+
r = setup_macvlan(arg_machine, pid, arg_network_macvlan);
if (r < 0)
goto finish;
@@ -3981,7 +4056,9 @@ int main(int argc, char *argv[]) {
}
expose_port_flush(arg_expose_ports, &exposed);
+
(void) remove_veth_links(veth_name, arg_network_veth_extra);
+ veth_created = false;
}
finish:
@@ -4014,7 +4091,10 @@ finish:
}
expose_port_flush(arg_expose_ports, &exposed);
- (void) remove_veth_links(veth_name, arg_network_veth_extra);
+
+ if (veth_created)
+ (void) remove_veth_links(veth_name, arg_network_veth_extra);
+ (void) remove_bridge(arg_network_zone);
free(arg_directory);
free(arg_template);
diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c
index e291758969..17eab9772e 100644
--- a/src/reply-password/reply-password.c
+++ b/src/reply-password/reply-password.c
@@ -26,14 +26,12 @@
#include "fd-util.h"
#include "log.h"
#include "macro.h"
+#include "socket-util.h"
#include "string-util.h"
#include "util.h"
static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) {
- union {
- struct sockaddr sa;
- struct sockaddr_un un;
- } sa = {
+ union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
@@ -43,7 +41,7 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0)
+ if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return log_error_errno(errno, "Failed to send: %m");
return 0;
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index 6805873f9e..4a4bd8d3b8 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -431,7 +431,7 @@ static int create_socket(char **name) {
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
RUN_WITH_UMASK(0177) {
- if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
}
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 94d1c1d63c..8f0df84793 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -221,7 +221,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
} else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
uint64_t u;
- r = cg_cpu_shares_parse(eq, &u);
+ r = cg_blkio_weight_parse(eq, &u);
if (r < 0) {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
@@ -347,7 +347,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
log_error("Failed to parse %s value %s.", field, weight);
return -EINVAL;
}
- r = sd_bus_message_append(m, "v", "a(st)", path, u);
+ r = sd_bus_message_append(m, "v", "a(st)", 1, path, u);
}
} else if (streq(field, "Nice")) {
@@ -1088,7 +1088,7 @@ static int dump_processes(
}
more = i+1 < n || cg->children;
- special = draw_special_char(more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT);
+ special = special_glyph(more ? TREE_BRANCH : TREE_RIGHT);
fprintf(stdout, "%s%s%*"PID_PRI" %s\n",
prefix,
@@ -1124,14 +1124,14 @@ static int dump_processes(
name++;
more = i+1 < n;
- special = draw_special_char(more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT);
+ special = special_glyph(more ? TREE_BRANCH : TREE_RIGHT);
fputs(prefix, stdout);
fputs(special, stdout);
fputs(name, stdout);
fputc('\n', stdout);
- special = draw_special_char(more ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE);
+ special = special_glyph(more ? TREE_VERTICAL : TREE_SPACE);
pp = strappend(prefix, special);
if (!pp)
@@ -1215,7 +1215,7 @@ static int dump_extra_processes(
fprintf(stdout, "%s%s %*" PID_PRI " %s\n",
prefix,
- draw_special_char(DRAW_TRIANGULAR_BULLET),
+ special_glyph(TRIANGULAR_BULLET),
width, pids[k],
name);
}
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 7539891bf2..3e451db715 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -76,9 +76,9 @@ static void show_pid_array(
get_process_cmdline(pids[i], n_columns, true, &t);
if (extra)
- printf("%s%s ", prefix, draw_special_char(DRAW_TRIANGULAR_BULLET));
+ printf("%s%s ", prefix, special_glyph(TRIANGULAR_BULLET));
else
- printf("%s%s", prefix, draw_special_char(((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)));
+ printf("%s%s", prefix, special_glyph(((more || i < n_pids-1) ? TREE_BRANCH : TREE_RIGHT)));
printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t));
}
@@ -172,10 +172,10 @@ int show_cgroup_by_path(
}
if (last) {
- printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), cg_unescape(basename(last)));
+ printf("%s%s%s\n", prefix, special_glyph(TREE_BRANCH), cg_unescape(basename(last)));
if (!p1) {
- p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL));
+ p1 = strappend(prefix, special_glyph(TREE_VERTICAL));
if (!p1)
return -ENOMEM;
}
@@ -195,7 +195,7 @@ int show_cgroup_by_path(
show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags);
if (last) {
- printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last)));
+ printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), cg_unescape(basename(last)));
if (!p2) {
p2 = strappend(prefix, " ");
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index 1141f9964f..83be79a4f5 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -37,6 +37,7 @@
#include "path-util.h"
#include "process-util.h"
#include "signal-util.h"
+#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
#include "syslog-util.h"
@@ -873,3 +874,40 @@ int config_parse_personality(
*personality = p;
return 0;
}
+
+int config_parse_ifname(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ char **s = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ *s = mfree(*s);
+ return 0;
+ }
+
+ if (!ifname_valid(rvalue)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ r = free_and_strdup(s, rvalue);
+ if (r < 0)
+ return log_oom();
+
+ return 0;
+}
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 73fb132413..f6964e3fd4 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -125,6 +125,7 @@ int config_parse_log_facility(const char *unit, const char *filename, unsigned l
int config_parse_log_level(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_personality(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_ifname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \
int function(const char *unit, \
diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c
index ade2de7727..97865eac4a 100644
--- a/src/shared/firewall-util.c
+++ b/src/shared/firewall-util.c
@@ -44,6 +44,7 @@
#include "firewall-util.h"
#include "in-addr-util.h"
#include "macro.h"
+#include "socket-util.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free);
@@ -59,10 +60,9 @@ static int entry_fill_basics(
assert(entry);
- if (out_interface && strlen(out_interface) >= IFNAMSIZ)
+ if (out_interface && !ifname_valid(out_interface))
return -EINVAL;
-
- if (in_interface && strlen(in_interface) >= IFNAMSIZ)
+ if (in_interface && !ifname_valid(in_interface))
return -EINVAL;
entry->ip.proto = protocol;
diff --git a/src/shared/generator.c b/src/shared/generator.c
index cd3c35cd55..70afc6a285 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -65,7 +65,7 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
"Description=File System Check on %2$s\n"
"DefaultDependencies=no\n"
"BindsTo=%3$s\n"
- "After=%3$s local-fs-pre.target\n"
+ "After=initrd-root-device.target local-fs-pre.target\n"
"Before=shutdown.target\n"
"\n"
"[Service]\n"
@@ -191,3 +191,17 @@ int generator_write_timeouts(
"[Unit]\nJobTimeoutSec=%s",
program_invocation_short_name, timeout);
}
+
+int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
+ _cleanup_free_ char *unit = NULL;
+ int r;
+
+ r = unit_name_from_path(what, ".device", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path: %m");
+
+ return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
+ "# Automatically generated by %s\n\n"
+ "[Unit]\nRequires=%s\nAfter=%s",
+ program_invocation_short_name, unit, unit);
+}
diff --git a/src/shared/generator.h b/src/shared/generator.h
index a734e13970..a6017c1b76 100644
--- a/src/shared/generator.h
+++ b/src/shared/generator.h
@@ -34,3 +34,7 @@ int generator_write_timeouts(
const char *where,
const char *opts,
char **filtered);
+
+int generator_write_initrd_root_device_deps(
+ const char *dir,
+ const char *what);
diff --git a/src/shared/install.c b/src/shared/install.c
index cc36da1853..64d66a45d3 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -40,6 +40,7 @@
#include "hashmap.h"
#include "install-printf.h"
#include "install.h"
+#include "locale-util.h"
#include "log.h"
#include "macro.h"
#include "mkdir.h"
@@ -116,6 +117,14 @@ bool unit_type_may_template(UnitType type) {
UNIT_PATH);
}
+static const char *unit_file_type_table[_UNIT_FILE_TYPE_MAX] = {
+ [UNIT_FILE_TYPE_REGULAR] = "regular",
+ [UNIT_FILE_TYPE_SYMLINK] = "symlink",
+ [UNIT_FILE_TYPE_MASKED] = "masked",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType);
+
static int in_search_path(const LookupPaths *p, const char *path) {
_cleanup_free_ char *parent = NULL;
char **i;
@@ -328,7 +337,10 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang
switch(changes[i].type) {
case UNIT_FILE_SYMLINK:
if (!quiet)
- log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source);
+ log_info("Created symlink %s %s %s.",
+ changes[i].path,
+ special_glyph(ARROW),
+ changes[i].source);
break;
case UNIT_FILE_UNLINK:
if (!quiet)
@@ -338,6 +350,11 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang
if (!quiet)
log_info("Unit %s is masked, ignoring.", changes[i].path);
break;
+ case UNIT_FILE_IS_DANGLING:
+ if (!quiet)
+ log_info("Unit %s is an alias to a unit that is not present, ignoring.",
+ changes[i].path);
+ break;
case -EEXIST:
if (changes[i].source)
log_error_errno(changes[i].type,
@@ -376,8 +393,6 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang
log_error_errno(r, "Failed to %s: %m.", verb);
}
-
-
static int create_symlink(
const char *old_path,
const char *new_path,
@@ -393,7 +408,11 @@ static int create_symlink(
/* Actually create a symlink, and remember that we did. Is
* smart enough to check if there's already a valid symlink in
- * place. */
+ * place.
+ *
+ * Returns 1 if a symlink was created or already exists and points to
+ * the right place, or negative on error.
+ */
mkdir_parents_label(new_path, 0755);
@@ -418,7 +437,7 @@ static int create_symlink(
}
if (path_equal(dest, old_path))
- return 0;
+ return 1;
if (!force) {
unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest);
@@ -1223,6 +1242,7 @@ static int unit_file_search(
const LookupPaths *paths,
SearchFlags flags) {
+ _cleanup_free_ char *template = NULL;
char **p;
int r;
@@ -1247,24 +1267,19 @@ static int unit_file_search(
return -ENOMEM;
r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
- if (r < 0) {
- if (r != -ENOENT)
- return r;
- } else {
+ if (r >= 0) {
info->path = path;
path = NULL;
return r;
- }
+ } else if (r != -ENOENT)
+ return r;
}
if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
-
/* Unit file doesn't exist, however instance
* enablement was requested. We will check if it is
* possible to load template unit file. */
- _cleanup_free_ char *template = NULL;
-
r = unit_name_template(info->name, &template);
if (r < 0)
return r;
@@ -1277,17 +1292,16 @@ static int unit_file_search(
return -ENOMEM;
r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
- if (r < 0) {
- if (r != -ENOENT)
- return r;
- } else {
+ if (r >= 0) {
info->path = path;
path = NULL;
return r;
- }
+ } else if (r != -ENOENT)
+ return r;
}
}
+ log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template));
return -ENOENT;
}
@@ -1319,6 +1333,11 @@ static int install_info_follow(
return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
}
+/**
+ * Search for the unit file. If the unit name is a symlink,
+ * follow the symlink to the target, maybe more than once.
+ * Propagate the instance name if present.
+ */
static int install_info_traverse(
UnitFileScope scope,
InstallContext *c,
@@ -1355,13 +1374,10 @@ static int install_info_traverse(
}
r = install_info_follow(c, i, paths->root_dir, flags);
- if (r < 0) {
+ if (r == -EXDEV) {
_cleanup_free_ char *buffer = NULL;
const char *bn;
- if (r != -EXDEV)
- return r;
-
/* Target has a different name, create a new
* install info object for that, and continue
* with that. */
@@ -1388,12 +1404,15 @@ static int install_info_traverse(
if (r < 0)
return r;
+ /* Try again, with the new target we found. */
r = unit_file_search(c, i, paths, flags);
- if (r < 0)
- return r;
+ if (r == -ENOENT)
+ /* Translate error code to highlight this specific case */
+ return -ENOLINK;
}
- /* Try again, with the new target we found. */
+ if (r < 0)
+ return r;
}
if (ret)
@@ -1689,11 +1708,17 @@ static int install_context_mark_for_removal(
return r;
r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
- if (r < 0)
+ if (r == -ENOLINK)
+ return 0;
+ else if (r < 0)
return r;
- if (i->type != UNIT_FILE_TYPE_REGULAR)
+ if (i->type != UNIT_FILE_TYPE_REGULAR) {
+ log_debug("Unit %s has type %s, ignoring.",
+ i->name,
+ unit_file_type_to_string(i->type) ?: "invalid");
continue;
+ }
r = mark_symlink_for_removal(remove_symlinks_to, i->name);
if (r < 0)
@@ -2788,6 +2813,9 @@ int unit_file_preset_all(
if (r == -ERFKILL)
r = unit_file_changes_add(changes, n_changes,
UNIT_FILE_IS_MASKED, de->d_name, NULL);
+ else if (r == -ENOLINK)
+ r = unit_file_changes_add(changes, n_changes,
+ UNIT_FILE_IS_DANGLING, de->d_name, NULL);
if (r < 0)
return r;
}
@@ -2911,6 +2939,7 @@ static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX]
[UNIT_FILE_SYMLINK] = "symlink",
[UNIT_FILE_UNLINK] = "unlink",
[UNIT_FILE_IS_MASKED] = "masked",
+ [UNIT_FILE_IS_DANGLING] = "dangling",
};
DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
diff --git a/src/shared/install.h b/src/shared/install.h
index 5812447c5b..c6aa4f6ef1 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -73,6 +73,7 @@ enum UnitFileChangeType {
UNIT_FILE_SYMLINK,
UNIT_FILE_UNLINK,
UNIT_FILE_IS_MASKED,
+ UNIT_FILE_IS_DANGLING,
_UNIT_FILE_CHANGE_TYPE_MAX,
_UNIT_FILE_CHANGE_INVALID = INT_MIN
};
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index 1157a0c72e..52b4db8875 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -400,28 +400,19 @@ static int resolve_remote(Connection *c) {
union sockaddr_union sa = {};
const char *node, *service;
- socklen_t salen;
int r;
if (path_is_absolute(arg_remote_host)) {
sa.un.sun_family = AF_UNIX;
- strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path)-1);
- sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
-
- salen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
-
- return connection_start(c, &sa.sa, salen);
+ strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path));
+ return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un));
}
if (arg_remote_host[0] == '@') {
sa.un.sun_family = AF_UNIX;
sa.un.sun_path[0] = 0;
- strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-2);
- sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
-
- salen = offsetof(union sockaddr_union, un.sun_path) + 1 + strlen(sa.un.sun_path + 1);
-
- return connection_start(c, &sa.sa, salen);
+ strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-1);
+ return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un));
}
service = strrchr(arg_remote_host, ':');
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 387de025c5..0faf37d320 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -483,7 +483,7 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
}
if (circle_len > 0)
- printf("%s%s%s ", on_circle, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_circle);
+ printf("%s%s%s ", on_circle, circle ? special_glyph(BLACK_CIRCLE) : " ", off_circle);
printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s",
on_active, id_len, id, off_active,
@@ -1355,7 +1355,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
} else
id_cols = max_id_len;
- if (!arg_no_legend)
+ if (!arg_no_legend && c > 0)
printf("%-*s %-*s\n",
id_cols, "UNIT FILE",
state_cols, "STATE");
@@ -1422,8 +1422,8 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
n_units = hashmap_size(h);
- units = new(UnitFileList, n_units);
- if (!units && n_units > 0) {
+ units = new(UnitFileList, n_units ?: 1); /* avoid malloc(0) */
+ if (!units) {
unit_file_list_free(h);
return log_oom();
}
@@ -1519,10 +1519,9 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
output_unit_file_list(units, c);
- if (install_client_side()) {
+ if (install_client_side())
for (unit = units; unit < units + c; unit++)
free(unit->path);
- }
return 0;
}
@@ -1541,7 +1540,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra
printf("%s...\n",max_len % 2 ? "" : " ");
return 0;
}
- printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE));
+ printf("%s", special_glyph(branches & (1 << i) ? TREE_VERTICAL : TREE_SPACE));
}
len += 2;
@@ -1550,7 +1549,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra
return 0;
}
- printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
+ printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH));
}
if (arg_full) {
@@ -1711,24 +1710,25 @@ static int list_dependencies_one(
const char *on;
(void) get_state_one_unit(bus, *c, &active_state);
+
switch (active_state) {
- case UNIT_ACTIVE:
- case UNIT_RELOADING:
- case UNIT_ACTIVATING:
- on = ansi_highlight_green();
- break;
-
- case UNIT_INACTIVE:
- case UNIT_DEACTIVATING:
- on = ansi_normal();
- break;
-
- default:
- on = ansi_highlight_red();
- break;
+ case UNIT_ACTIVE:
+ case UNIT_RELOADING:
+ case UNIT_ACTIVATING:
+ on = ansi_highlight_green();
+ break;
+
+ case UNIT_INACTIVE:
+ case UNIT_DEACTIVATING:
+ on = ansi_normal();
+ break;
+
+ default:
+ on = ansi_highlight_red();
+ break;
}
- printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal());
+ printf("%s%s%s ", on, special_glyph(BLACK_CIRCLE), ansi_normal());
}
r = list_dependencies_print(*c, level, branches, c[1] == NULL);
@@ -1965,7 +1965,7 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n)
on_failed = off_failed = "";
if (circle_len > 0)
- printf("%s%s%s ", on_state, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_state);
+ printf("%s%s%s ", on_state, circle ? special_glyph(BLACK_CIRCLE) : " ", off_state);
if (m->is_host)
printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
@@ -3528,7 +3528,7 @@ static void print_status_info(
} else
active_on = active_off = "";
- printf("%s%s%s %s", active_on, draw_special_char(DRAW_BLACK_CIRCLE), active_off, strna(i->id));
+ printf("%s%s%s %s", active_on, special_glyph(BLACK_CIRCLE), active_off, strna(i->id));
if (i->description && !streq_ptr(i->id, i->description))
printf(" - %s", i->description);
@@ -3583,7 +3583,7 @@ static void print_status_info(
}
printf("%s\n %s", dir,
- draw_special_char(DRAW_TREE_RIGHT));
+ special_glyph(TREE_RIGHT));
}
last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
@@ -4705,7 +4705,7 @@ static int show_system_status(sd_bus *bus) {
} else
on = off = "";
- printf("%s%s%s %s\n", on, draw_special_char(DRAW_BLACK_CIRCLE), off, arg_host ? arg_host : hn);
+ printf("%s%s%s %s\n", on, special_glyph(BLACK_CIRCLE), off, arg_host ? arg_host : hn);
printf(" State: %s%s%s\n",
on, strna(mi.state), off);
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index 33ff3755bc..b480fdaa9c 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -27,6 +27,29 @@
#include "string-util.h"
#include "util.h"
+static void test_ifname_valid(void) {
+ assert(ifname_valid("foo"));
+ assert(ifname_valid("eth0"));
+
+ assert(!ifname_valid("0"));
+ assert(!ifname_valid("99"));
+ assert(ifname_valid("a99"));
+ assert(ifname_valid("99a"));
+
+ assert(!ifname_valid(NULL));
+ assert(!ifname_valid(""));
+ assert(!ifname_valid(" "));
+ assert(!ifname_valid(" foo"));
+ assert(!ifname_valid("bar\n"));
+ assert(!ifname_valid("."));
+ assert(!ifname_valid(".."));
+ assert(ifname_valid("foo.bar"));
+ assert(!ifname_valid("x:y"));
+
+ assert(ifname_valid("xxxxxxxxxxxxxxx"));
+ assert(!ifname_valid("xxxxxxxxxxxxxxxx"));
+}
+
static void test_socket_address_parse(void) {
SocketAddress a;
@@ -343,10 +366,27 @@ static void test_sockaddr_equal(void) {
assert_se(!sockaddr_equal(&b, &c));
}
+static void test_sockaddr_un_len(void) {
+ static const struct sockaddr_un fs = {
+ .sun_family = AF_UNIX,
+ .sun_path = "/foo/bar/waldo",
+ };
+
+ static const struct sockaddr_un abstract = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0foobar",
+ };
+
+ assert_se(SOCKADDR_UN_LEN(fs) == offsetof(struct sockaddr_un, sun_path) + strlen(fs.sun_path));
+ assert_se(SOCKADDR_UN_LEN(abstract) == offsetof(struct sockaddr_un, sun_path) + 1 + strlen(abstract.sun_path + 1));
+}
+
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
+ test_ifname_valid();
+
test_socket_address_parse();
test_socket_address_parse_netlink();
test_socket_address_equal();
@@ -363,5 +403,7 @@ int main(int argc, char *argv[]) {
test_sockaddr_equal();
+ test_sockaddr_un_len();
+
return 0;
}
diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c
index c7ded451a2..ee879c7b89 100644
--- a/src/tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent/tty-ask-password-agent.c
@@ -65,8 +65,8 @@ static int ask_password_plymouth(
const char *flag_file,
char ***ret) {
+ static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_close_ int fd = -1, notify = -1;
- union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_free_ char *packet = NULL;
ssize_t k;
int r, n;
@@ -94,7 +94,7 @@ static int ask_password_plymouth(
if (fd < 0)
return -errno;
- r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return -errno;
@@ -269,8 +269,7 @@ static int send_passwords(const char *socket_name, char **passwords) {
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa,
- offsetof(struct sockaddr_un, sun_path) + strlen(socket_name));
+ r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
r = log_debug_errno(errno, "sendto(): %m");
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index 962de22f43..f68a09d7a8 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -105,7 +105,7 @@ struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) {
uctrl->saddr.un.sun_family = AF_LOCAL;
strscpy(uctrl->saddr.un.sun_path, sizeof(uctrl->saddr.un.sun_path), "/run/udev/control");
- uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.un.sun_path);
+ uctrl->addrlen = SOCKADDR_UN_LEN(uctrl->saddr.un);
return uctrl;
}
diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c
index 8a1b824e65..08ae4aad27 100644
--- a/src/vconsole/vconsole-setup.c
+++ b/src/vconsole/vconsole-setup.c
@@ -195,9 +195,15 @@ static void font_copy_to_all_vcs(int fd) {
unsigned char map8[E_TABSZ];
unsigned short map16[E_TABSZ];
struct unimapdesc unimapd;
- struct unipair unipairs[USHRT_MAX];
+ _cleanup_free_ struct unipair* unipairs = NULL;
int i, r;
+ unipairs = new(struct unipair, USHRT_MAX);
+ if (unipairs == NULL) {
+ log_error("Not enough memory to copy fonts");
+ return;
+ }
+
/* get active, and 16 bit mask of used VT numbers */
r = ioctl(fd, VT_GETSTATE, &vcs);
if (r < 0) {