|
|
1abbee |
From 603edc22d0516044b72b09ed94a696edd2de7f37 Mon Sep 17 00:00:00 2001
|
|
|
1abbee |
From: Lennart Poettering <lennart@poettering.net>
|
|
|
1abbee |
Date: Wed, 10 Jun 2015 19:10:47 +0200
|
|
|
1abbee |
Subject: [PATCH] util: introduce CMSG_FOREACH() macro and make use of it
|
|
|
1abbee |
everywhere
|
|
|
1abbee |
|
|
|
1abbee |
It's only marginally shorter then the usual for() loop, but certainly
|
|
|
1abbee |
more readable.
|
|
|
1abbee |
|
|
|
1abbee |
Cherry-picked from: 2a1288ff89322a2f49c79f6d1832c8164c14a05c
|
|
|
1abbee |
Related: #1318994
|
|
|
1abbee |
---
|
|
|
1abbee |
src/core/manager.c | 2 +-
|
|
|
1abbee |
src/core/namespace.c | 3 +--
|
|
|
1abbee |
src/import/importd.c | 8 ++------
|
|
|
1abbee |
src/journal/journald-server.c | 2 +-
|
|
|
1abbee |
src/libsystemd-network/sd-dhcp-client.c | 2 +-
|
|
|
1abbee |
src/libsystemd-network/sd-dhcp-server.c | 2 +-
|
|
|
1abbee |
src/libsystemd/sd-bus/bus-container.c | 2 +-
|
|
|
1abbee |
src/libsystemd/sd-bus/bus-socket.c | 16 ++++++++++------
|
|
|
1abbee |
src/libsystemd/sd-rtnl/rtnl-message.c | 2 +-
|
|
|
1abbee |
src/resolve/resolved-dns-stream.c | 3 ++-
|
|
|
1abbee |
src/resolve/resolved-manager.c | 2 +-
|
|
|
1abbee |
src/shared/macro.h | 3 +++
|
|
|
1abbee |
src/shared/util.c | 12 +++++++++++-
|
|
|
1abbee |
src/shared/util.h | 2 ++
|
|
|
1abbee |
src/timesync/timesyncd-manager.c | 2 +-
|
|
|
1abbee |
15 files changed, 39 insertions(+), 24 deletions(-)
|
|
|
1abbee |
|
|
|
1abbee |
diff --git a/src/core/manager.c b/src/core/manager.c
|
|
Pablo Greco |
48fc63 |
index c5021993e5..71dd70c94c 100644
|
|
|
1abbee |
--- a/src/core/manager.c
|
|
|
1abbee |
+++ b/src/core/manager.c
|
|
|
1abbee |
@@ -1679,7 +1679,7 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
|
|
|
1abbee |
return -errno;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &msghdr) {
|
|
|
1abbee |
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
|
|
|
1abbee |
|
|
|
1abbee |
fd_array = (int*) CMSG_DATA(cmsg);
|
|
|
1abbee |
diff --git a/src/core/namespace.c b/src/core/namespace.c
|
|
Pablo Greco |
48fc63 |
index ebd5fb3347..00495c1446 100644
|
|
|
1abbee |
--- a/src/core/namespace.c
|
|
|
1abbee |
+++ b/src/core/namespace.c
|
|
|
1abbee |
@@ -658,12 +658,11 @@ int setup_netns(int netns_storage_socket[2]) {
|
|
|
1abbee |
} else {
|
|
|
1abbee |
/* Yay, found something, so let's join the namespace */
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &mh)
|
|
|
1abbee |
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
|
|
|
1abbee |
assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
|
|
|
1abbee |
netns = *(int*) CMSG_DATA(cmsg);
|
|
|
1abbee |
}
|
|
|
1abbee |
- }
|
|
|
1abbee |
|
|
|
1abbee |
if (setns(netns, CLONE_NEWNET) < 0) {
|
|
|
1abbee |
r = -errno;
|
|
|
1abbee |
diff --git a/src/import/importd.c b/src/import/importd.c
|
|
Pablo Greco |
48fc63 |
index 9aaf991f83..a29630b12b 100644
|
|
|
1abbee |
--- a/src/import/importd.c
|
|
|
1abbee |
+++ b/src/import/importd.c
|
|
|
1abbee |
@@ -507,12 +507,8 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void
|
|
|
1abbee |
return -errno;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
|
|
|
1abbee |
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
|
|
|
1abbee |
- close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
|
|
|
1abbee |
- log_warning("Somebody sent us unexpected fds, ignoring.");
|
|
|
1abbee |
- return 0;
|
|
|
1abbee |
- } else if (cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &msghdr) {
|
|
|
1abbee |
+ if (cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
1abbee |
cmsg->cmsg_type == SCM_CREDENTIALS &&
|
|
|
1abbee |
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
|
|
|
1abbee |
|
|
|
1abbee |
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
|
|
Pablo Greco |
48fc63 |
index 6a35ebbde0..1eb1394d10 100644
|
|
|
1abbee |
--- a/src/journal/journald-server.c
|
|
|
1abbee |
+++ b/src/journal/journald-server.c
|
|
|
1abbee |
@@ -1176,7 +1176,7 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
|
|
|
1abbee |
return -errno;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &msghdr) {
|
|
|
1abbee |
|
|
|
1abbee |
if (cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
1abbee |
cmsg->cmsg_type == SCM_CREDENTIALS &&
|
|
|
1abbee |
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
|
|
Pablo Greco |
48fc63 |
index 5f90617b9e..870850ed36 100644
|
|
|
1abbee |
--- a/src/libsystemd-network/sd-dhcp-client.c
|
|
|
1abbee |
+++ b/src/libsystemd-network/sd-dhcp-client.c
|
|
|
1abbee |
@@ -1590,7 +1590,7 @@ static int client_receive_message_raw(sd_event_source *s, int fd,
|
|
|
1abbee |
} else if ((size_t)len < sizeof(DHCPPacket))
|
|
|
1abbee |
return 0;
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&msg;; cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &msg) {
|
|
|
1abbee |
if (cmsg->cmsg_level == SOL_PACKET &&
|
|
|
1abbee |
cmsg->cmsg_type == PACKET_AUXDATA &&
|
|
|
1abbee |
cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) {
|
|
|
1abbee |
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
|
|
Pablo Greco |
48fc63 |
index 0f284eb6a1..c9d0ace728 100644
|
|
|
1abbee |
--- a/src/libsystemd-network/sd-dhcp-server.c
|
|
|
1abbee |
+++ b/src/libsystemd-network/sd-dhcp-server.c
|
|
|
1abbee |
@@ -903,7 +903,7 @@ static int server_receive_message(sd_event_source *s, int fd,
|
|
|
1abbee |
else if ((size_t)len < sizeof(DHCPMessage))
|
|
|
1abbee |
return 0;
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&msg;; cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &msg) {
|
|
|
1abbee |
if (cmsg->cmsg_level == IPPROTO_IP &&
|
|
|
1abbee |
cmsg->cmsg_type == IP_PKTINFO &&
|
|
|
1abbee |
cmsg->cmsg_len == CMSG_LEN(sizeof(struct in_pktinfo))) {
|
|
|
1abbee |
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
|
|
Pablo Greco |
48fc63 |
index d29b98a269..10ab714312 100644
|
|
|
1abbee |
--- a/src/libsystemd/sd-bus/bus-container.c
|
|
|
1abbee |
+++ b/src/libsystemd/sd-bus/bus-container.c
|
|
|
1abbee |
@@ -222,7 +222,7 @@ int bus_container_connect_kernel(sd_bus *b) {
|
|
|
1abbee |
if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
|
|
|
1abbee |
return -errno;
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &mh)
|
|
|
1abbee |
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
|
|
|
1abbee |
int *fds;
|
|
|
1abbee |
unsigned n_fds;
|
|
|
1abbee |
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
|
|
Pablo Greco |
48fc63 |
index a3c3a45b46..ab56ef4f33 100644
|
|
|
1abbee |
--- a/src/libsystemd/sd-bus/bus-socket.c
|
|
|
1abbee |
+++ b/src/libsystemd/sd-bus/bus-socket.c
|
|
|
1abbee |
@@ -503,7 +503,6 @@ static int bus_socket_read_auth(sd_bus *b) {
|
|
|
1abbee |
struct cmsghdr cmsghdr;
|
|
|
1abbee |
uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)];
|
|
|
1abbee |
} control;
|
|
|
1abbee |
- struct cmsghdr *cmsg;
|
|
|
1abbee |
bool handle_cmsg = false;
|
|
|
1abbee |
|
|
|
1abbee |
assert(b);
|
|
|
1abbee |
@@ -554,8 +553,10 @@ static int bus_socket_read_auth(sd_bus *b) {
|
|
|
1abbee |
|
|
|
1abbee |
b->rbuffer_size += k;
|
|
|
1abbee |
|
|
|
1abbee |
- if (handle_cmsg)
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
|
|
|
1abbee |
+ if (handle_cmsg) {
|
|
|
1abbee |
+ struct cmsghdr *cmsg;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &mh)
|
|
|
1abbee |
if (cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
1abbee |
cmsg->cmsg_type == SCM_RIGHTS) {
|
|
|
1abbee |
int j;
|
|
|
1abbee |
@@ -569,6 +570,7 @@ static int bus_socket_read_auth(sd_bus *b) {
|
|
|
1abbee |
} else
|
|
|
1abbee |
log_debug("Got unexpected auxiliary data with level=%d and type=%d",
|
|
|
1abbee |
cmsg->cmsg_level, cmsg->cmsg_type);
|
|
|
1abbee |
+ }
|
|
|
1abbee |
|
|
|
1abbee |
r = bus_socket_auth_verify(b);
|
|
|
1abbee |
if (r != 0)
|
|
|
1abbee |
@@ -930,7 +932,6 @@ int bus_socket_read_message(sd_bus *bus) {
|
|
|
1abbee |
struct cmsghdr cmsghdr;
|
|
|
1abbee |
uint8_t buf[CMSG_SPACE(sizeof(int) * BUS_FDS_MAX)];
|
|
|
1abbee |
} control;
|
|
|
1abbee |
- struct cmsghdr *cmsg;
|
|
|
1abbee |
bool handle_cmsg = false;
|
|
|
1abbee |
|
|
|
1abbee |
assert(bus);
|
|
|
1abbee |
@@ -976,8 +977,10 @@ int bus_socket_read_message(sd_bus *bus) {
|
|
|
1abbee |
|
|
|
1abbee |
bus->rbuffer_size += k;
|
|
|
1abbee |
|
|
|
1abbee |
- if (handle_cmsg)
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
|
|
|
1abbee |
+ if (handle_cmsg) {
|
|
|
1abbee |
+ struct cmsghdr *cmsg;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &mh)
|
|
|
1abbee |
if (cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
1abbee |
cmsg->cmsg_type == SCM_RIGHTS) {
|
|
|
1abbee |
int n, *f;
|
|
|
1abbee |
@@ -1005,6 +1008,7 @@ int bus_socket_read_message(sd_bus *bus) {
|
|
|
1abbee |
} else
|
|
|
1abbee |
log_debug("Got unexpected auxiliary data with level=%d and type=%d",
|
|
|
1abbee |
cmsg->cmsg_level, cmsg->cmsg_type);
|
|
|
1abbee |
+ }
|
|
|
1abbee |
|
|
|
1abbee |
r = bus_socket_read_message_need(bus, &need);
|
|
|
1abbee |
if (r < 0)
|
|
|
1abbee |
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
|
|
Pablo Greco |
48fc63 |
index 9276bbdebc..cc84253f1d 100644
|
|
|
1abbee |
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
|
|
|
1abbee |
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
|
|
|
1abbee |
@@ -1444,7 +1444,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool
|
|
|
1abbee |
return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&msg;; cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &msg) {
|
|
|
1abbee |
if (cmsg->cmsg_level == SOL_SOCKET &&
|
|
|
1abbee |
cmsg->cmsg_type == SCM_CREDENTIALS &&
|
|
|
1abbee |
cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
|
|
|
1abbee |
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
|
|
Pablo Greco |
48fc63 |
index 4c0b557bad..7f47e7223a 100644
|
|
|
1abbee |
--- a/src/resolve/resolved-dns-stream.c
|
|
|
1abbee |
+++ b/src/resolve/resolved-dns-stream.c
|
|
|
1abbee |
@@ -113,7 +113,8 @@ static int dns_stream_identify(DnsStream *s) {
|
|
|
1abbee |
|
|
|
1abbee |
mh.msg_control = &control;
|
|
|
1abbee |
mh.msg_controllen = sl;
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
|
|
|
1abbee |
+
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &mh) {
|
|
|
1abbee |
|
|
|
1abbee |
if (cmsg->cmsg_level == IPPROTO_IPV6) {
|
|
|
1abbee |
assert(s->peer.sa.sa_family == AF_INET6);
|
|
|
1abbee |
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
|
|
Pablo Greco |
48fc63 |
index 7c253aa13f..173ab8a148 100644
|
|
|
1abbee |
--- a/src/resolve/resolved-manager.c
|
|
|
1abbee |
+++ b/src/resolve/resolved-manager.c
|
|
|
1abbee |
@@ -920,7 +920,7 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) {
|
|
|
1abbee |
} else
|
|
|
1abbee |
return -EAFNOSUPPORT;
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &mh) {
|
|
|
1abbee |
|
|
|
1abbee |
if (cmsg->cmsg_level == IPPROTO_IPV6) {
|
|
|
1abbee |
assert(p->family == AF_INET6);
|
|
|
1abbee |
diff --git a/src/shared/macro.h b/src/shared/macro.h
|
|
Pablo Greco |
48fc63 |
index 9d857dc8d7..7a57f4e5b1 100644
|
|
|
1abbee |
--- a/src/shared/macro.h
|
|
|
1abbee |
+++ b/src/shared/macro.h
|
|
|
1abbee |
@@ -471,4 +471,7 @@ static inline bool GID_IS_INVALID(gid_t gid) {
|
|
|
1abbee |
} \
|
|
|
1abbee |
struct __useless_struct_to_allow_trailing_semicolon__
|
|
|
1abbee |
|
|
|
1abbee |
+#define CMSG_FOREACH(cmsg, mh) \
|
|
|
1abbee |
+ for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
|
|
|
1abbee |
+
|
|
|
1abbee |
#include "log.h"
|
|
|
1abbee |
diff --git a/src/shared/util.c b/src/shared/util.c
|
|
Pablo Greco |
48fc63 |
index 4c441a5448..357fbfe7dc 100644
|
|
|
1abbee |
--- a/src/shared/util.c
|
|
|
1abbee |
+++ b/src/shared/util.c
|
|
|
1abbee |
@@ -7887,7 +7887,7 @@ int openpt_in_namespace(pid_t pid, int flags) {
|
|
|
1abbee |
if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
|
|
|
1abbee |
return -errno;
|
|
|
1abbee |
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &mh)
|
|
|
1abbee |
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
|
|
|
1abbee |
int *fds;
|
|
|
1abbee |
unsigned n_fds;
|
|
|
1abbee |
@@ -8375,6 +8375,16 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
|
|
|
1abbee |
return -1;
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
+void cmsg_close_all(struct msghdr *mh) {
|
|
|
1abbee |
+ struct cmsghdr *cmsg;
|
|
|
1abbee |
+
|
|
|
1abbee |
+ assert(mh);
|
|
|
1abbee |
+
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, mh)
|
|
|
1abbee |
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
|
|
|
1abbee |
+ close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
|
|
|
1abbee |
+}
|
|
|
1abbee |
+
|
|
|
1abbee |
char *shell_maybe_quote(const char *s) {
|
|
|
1abbee |
const char *p;
|
|
|
1abbee |
char *r, *t;
|
|
|
1abbee |
diff --git a/src/shared/util.h b/src/shared/util.h
|
|
Pablo Greco |
48fc63 |
index be04524cc9..12afcc3429 100644
|
|
|
1abbee |
--- a/src/shared/util.h
|
|
|
1abbee |
+++ b/src/shared/util.h
|
|
|
1abbee |
@@ -1082,6 +1082,8 @@ void sigkill_wait(pid_t *pid);
|
|
|
1abbee |
|
|
|
1abbee |
int syslog_parse_priority(const char **p, int *priority, bool with_facility);
|
|
|
1abbee |
|
|
|
1abbee |
+void cmsg_close_all(struct msghdr *mh);
|
|
|
1abbee |
+
|
|
|
1abbee |
char *shell_maybe_quote(const char *s);
|
|
|
1abbee |
|
|
|
1abbee |
typedef enum ExtractFlags {
|
|
|
1abbee |
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
|
|
Pablo Greco |
48fc63 |
index 73ac7eecbf..5cc1968204 100644
|
|
|
1abbee |
--- a/src/timesync/timesyncd-manager.c
|
|
|
1abbee |
+++ b/src/timesync/timesyncd-manager.c
|
|
|
1abbee |
@@ -539,7 +539,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
|
|
|
1abbee |
}
|
|
|
1abbee |
|
|
|
1abbee |
recv_time = NULL;
|
|
|
1abbee |
- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
|
|
|
1abbee |
+ CMSG_FOREACH(cmsg, &msghdr) {
|
|
|
1abbee |
if (cmsg->cmsg_level != SOL_SOCKET)
|
|
|
1abbee |
continue;
|
|
|
1abbee |
|