summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/basic/btrfs-util.c39
-rw-r--r--src/basic/btrfs-util.h4
-rw-r--r--src/basic/in-addr-util.c43
-rw-r--r--src/basic/in-addr-util.h7
-rw-r--r--src/basic/missing.h4
-rw-r--r--src/import/pull-common.c12
-rw-r--r--src/libsystemd-network/ndisc-router.c2
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c32
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c19
-rw-r--r--src/network/networkd-dhcp4.c44
-rw-r--r--src/network/networkd-link.c50
-rw-r--r--src/network/networkd-manager.c56
-rw-r--r--src/network/networkd-network-gperf.gperf2
-rw-r--r--src/network/networkd-network.c87
-rw-r--r--src/network/networkd-network.h24
-rw-r--r--src/nspawn/nspawn-mount.c24
-rw-r--r--src/nspawn/nspawn.c123
-rw-r--r--src/shared/dns-domain.c12
-rw-r--r--src/shared/dns-domain.h2
-rw-r--r--src/shared/machine-image.c39
-rw-r--r--src/test/test-dns-domain.c13
21 files changed, 450 insertions, 188 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 656bb13719..5f9e21dcba 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <linux/fs.h>
#include <linux/loop.h>
#include <stddef.h>
#include <stdio.h>
@@ -38,6 +39,7 @@
#include "alloc-util.h"
#include "btrfs-ctree.h"
#include "btrfs-util.h"
+#include "chattr-util.h"
#include "copy.h"
#include "fd-util.h"
#include "fileio.h"
@@ -45,6 +47,7 @@
#include "macro.h"
#include "missing.h"
#include "path-util.h"
+#include "rm-rf.h"
#include "selinux-util.h"
#include "smack-util.h"
#include "sparse-endian.h"
@@ -1718,28 +1721,46 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
if (r < 0)
return r;
if (r == 0) {
+ bool plain_directory = false;
+
+ /* If the source isn't a proper subvolume, fail unless fallback is requested */
if (!(flags & BTRFS_SNAPSHOT_FALLBACK_COPY))
return -EISDIR;
r = btrfs_subvol_make(new_path);
- if (r < 0)
+ if (r == -ENOTTY && (flags & BTRFS_SNAPSHOT_FALLBACK_DIRECTORY)) {
+ /* If the destination doesn't support subvolumes, then use a plain directory, if that's requested. */
+ if (mkdir(new_path, 0755) < 0)
+ return r;
+
+ plain_directory = true;
+ } else if (r < 0)
return r;
r = copy_directory_fd(old_fd, new_path, true);
- if (r < 0) {
- (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
- return r;
- }
+ if (r < 0)
+ goto fallback_fail;
if (flags & BTRFS_SNAPSHOT_READ_ONLY) {
- r = btrfs_subvol_set_read_only(new_path, true);
- if (r < 0) {
- (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA);
- return r;
+
+ if (plain_directory) {
+ /* Plain directories have no recursive read-only flag, but something pretty close to
+ * it: the IMMUTABLE bit. Let's use this here, if this is requested. */
+
+ if (flags & BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE)
+ (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
+ } else {
+ r = btrfs_subvol_set_read_only(new_path, true);
+ if (r < 0)
+ goto fallback_fail;
}
}
return 0;
+
+ fallback_fail:
+ (void) rm_rf(new_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+ return r;
}
r = extract_subvolume_name(new_path, &subvolume);
diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h
index 1d852d502c..04a2e1274b 100644
--- a/src/basic/btrfs-util.h
+++ b/src/basic/btrfs-util.h
@@ -45,10 +45,12 @@ typedef struct BtrfsQuotaInfo {
} BtrfsQuotaInfo;
typedef enum BtrfsSnapshotFlags {
- BTRFS_SNAPSHOT_FALLBACK_COPY = 1,
+ BTRFS_SNAPSHOT_FALLBACK_COPY = 1, /* If the source isn't a subvolume, reflink everything */
BTRFS_SNAPSHOT_READ_ONLY = 2,
BTRFS_SNAPSHOT_RECURSIVE = 4,
BTRFS_SNAPSHOT_QUOTA = 8,
+ BTRFS_SNAPSHOT_FALLBACK_DIRECTORY = 16, /* If the destination doesn't support subvolumes, reflink/copy instead */
+ BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE = 32, /* When we can't create a subvolume, use the FS_IMMUTABLE attribute for indicating read-only */
} BtrfsSnapshotFlags;
typedef enum BtrfsRemoveFlags {
diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c
index aa7ccd1afd..3b06cb00ad 100644
--- a/src/basic/in-addr-util.c
+++ b/src/basic/in-addr-util.c
@@ -31,15 +31,9 @@
#include "util.h"
bool in4_addr_is_null(const struct in_addr *a) {
- return a->s_addr == 0;
-}
+ assert(a);
-bool in6_addr_is_null(const struct in6_addr *a) {
- return
- a->s6_addr32[0] == 0 &&
- a->s6_addr32[1] == 0 &&
- a->s6_addr32[2] == 0 &&
- a->s6_addr32[3] == 0;
+ return a->s_addr == 0;
}
int in_addr_is_null(int family, const union in_addr_union *u) {
@@ -49,16 +43,22 @@ int in_addr_is_null(int family, const union in_addr_union *u) {
return in4_addr_is_null(&u->in);
if (family == AF_INET6)
- return in6_addr_is_null(&u->in6);
+ return IN6_IS_ADDR_UNSPECIFIED(&u->in6);
return -EAFNOSUPPORT;
}
+bool in4_addr_is_link_local(const struct in_addr *a) {
+ assert(a);
+
+ return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
+}
+
int in_addr_is_link_local(int family, const union in_addr_union *u) {
assert(u);
if (family == AF_INET)
- return (be32toh(u->in.s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16);
+ return in4_addr_is_link_local(&u->in);
if (family == AF_INET6)
return IN6_IS_ADDR_LINKLOCAL(&u->in6);
@@ -66,12 +66,18 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) {
return -EAFNOSUPPORT;
}
+bool in4_addr_is_localhost(const struct in_addr *a) {
+ assert(a);
+
+ /* All of 127.x.x.x is localhost. */
+ return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
+}
+
int in_addr_is_localhost(int family, const union in_addr_union *u) {
assert(u);
if (family == AF_INET)
- /* All of 127.x.x.x is localhost. */
- return (be32toh(u->in.s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
+ return in4_addr_is_localhost(&u->in);
if (family == AF_INET6)
return IN6_IS_ADDR_LOOPBACK(&u->in6);
@@ -277,15 +283,14 @@ fallback:
}
int in_addr_from_string(int family, const char *s, union in_addr_union *ret) {
-
+ union in_addr_union buffer;
assert(s);
- assert(ret);
if (!IN_SET(family, AF_INET, AF_INET6))
return -EAFNOSUPPORT;
errno = 0;
- if (inet_pton(family, s, ret) <= 0)
+ if (inet_pton(family, s, ret ?: &buffer) <= 0)
return errno > 0 ? -errno : -EINVAL;
return 0;
@@ -295,18 +300,18 @@ int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *re
int r;
assert(s);
- assert(family);
- assert(ret);
r = in_addr_from_string(AF_INET, s, ret);
if (r >= 0) {
- *family = AF_INET;
+ if (family)
+ *family = AF_INET;
return 0;
}
r = in_addr_from_string(AF_INET6, s, ret);
if (r >= 0) {
- *family = AF_INET6;
+ if (family)
+ *family = AF_INET6;
return 0;
}
diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h
index d60064aef8..64a812c322 100644
--- a/src/basic/in-addr-util.h
+++ b/src/basic/in-addr-util.h
@@ -37,11 +37,14 @@ struct in_addr_data {
};
bool in4_addr_is_null(const struct in_addr *a);
-bool in6_addr_is_null(const struct in6_addr *a);
-
int in_addr_is_null(int family, const union in_addr_union *u);
+
+bool in4_addr_is_link_local(const struct in_addr *a);
int in_addr_is_link_local(int family, const union in_addr_union *u);
+
+bool in4_addr_is_localhost(const struct in_addr *a);
int in_addr_is_localhost(int family, const union in_addr_union *u);
+
int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b);
int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen);
int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen);
diff --git a/src/basic/missing.h b/src/basic/missing.h
index a5ae5d9e79..8833617dc6 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -143,6 +143,10 @@
#define GRND_RANDOM 0x0002
#endif
+#ifndef FS_NOCOW_FL
+#define FS_NOCOW_FL 0x00800000
+#endif
+
#ifndef BTRFS_IOCTL_MAGIC
#define BTRFS_IOCTL_MAGIC 0x94
#endif
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index 2ae2a4174c..5ddc0c56f4 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -144,12 +144,12 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
if (force_local)
(void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
- r = btrfs_subvol_snapshot(final, p, BTRFS_SNAPSHOT_QUOTA);
- if (r == -ENOTTY) {
- r = copy_tree(final, p, false);
- if (r < 0)
- return log_error_errno(r, "Failed to copy image: %m");
- } else if (r < 0)
+ r = btrfs_subvol_snapshot(final, p,
+ BTRFS_SNAPSHOT_QUOTA|
+ BTRFS_SNAPSHOT_FALLBACK_COPY|
+ BTRFS_SNAPSHOT_FALLBACK_DIRECTORY|
+ BTRFS_SNAPSHOT_RECURSIVE);
+ if (r < 0)
return log_error_errno(r, "Failed to create local image: %m");
log_info("Created new local image '%s'.", local);
diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/ndisc-router.c
index 41ff2b353a..cf56c89d76 100644
--- a/src/libsystemd-network/ndisc-router.c
+++ b/src/libsystemd-network/ndisc-router.c
@@ -91,7 +91,7 @@ _public_ int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *r
assert_return(rt, -EINVAL);
assert_return(ret_addr, -EINVAL);
- if (in6_addr_is_null(&rt->address))
+ if (IN6_IS_ADDR_UNSPECIFIED(&rt->address))
return -ENODATA;
*ret_addr = rt->address;
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index 6475da2c2a..1423264806 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -386,45 +386,23 @@ int sd_dhcp_client_set_hostname(
sd_dhcp_client *client,
const char *hostname) {
- char *new_hostname = NULL;
-
assert_return(client, -EINVAL);
- if (!hostname_is_valid(hostname, false) && !dns_name_is_valid(hostname))
+ /* Refuse hostnames that neither qualify as DNS nor as Linux hosntames */
+ if (hostname &&
+ !(hostname_is_valid(hostname, false) || dns_name_is_valid(hostname) > 0))
return -EINVAL;
- if (streq_ptr(client->hostname, hostname))
- return 0;
-
- if (hostname) {
- new_hostname = strdup(hostname);
- if (!new_hostname)
- return -ENOMEM;
- }
-
- free(client->hostname);
- client->hostname = new_hostname;
-
- return 0;
+ return free_and_strdup(&client->hostname, hostname);
}
int sd_dhcp_client_set_vendor_class_identifier(
sd_dhcp_client *client,
const char *vci) {
- char *new_vci = NULL;
-
assert_return(client, -EINVAL);
- new_vci = strdup(vci);
- if (!new_vci)
- return -ENOMEM;
-
- free(client->vendor_class_identifier);
-
- client->vendor_class_identifier = new_vci;
-
- return 0;
+ return free_and_strdup(&client->vendor_class_identifier, vci);
}
int sd_dhcp_client_set_client_port(
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index 8387b185c0..7fed55c5fc 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -383,6 +383,23 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
return 0;
}
+static void filter_bogus_addresses(struct in_addr *addresses, size_t *n) {
+ size_t i, j;
+
+ /* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */
+
+ for (i = 0, j = 0; i < *n; i ++) {
+
+ if (in4_addr_is_null(addresses+i) ||
+ in4_addr_is_localhost(addresses+i))
+ continue;
+
+ addresses[j++] = addresses[i];
+ }
+
+ *n = j;
+}
+
static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) {
assert(option);
assert(ret);
@@ -404,6 +421,8 @@ static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_add
if (!addresses)
return -ENOMEM;
+ filter_bogus_addresses(addresses, &n_addresses);
+
free(*ret);
*ret = addresses;
*n_ret = n_addresses;
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 614bceefab..ca23c1c2a7 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -536,6 +536,28 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
return;
}
+static int dhcp4_set_hostname(Link *link) {
+ _cleanup_free_ char *hostname = NULL;
+ const char *hn;
+ int r;
+
+ assert(link);
+
+ if (!link->network->dhcp_send_hostname)
+ hn = NULL;
+ else if (link->network->dhcp_hostname)
+ hn = link->network->dhcp_hostname;
+ else {
+ r = gethostname_strict(&hostname);
+ if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
+ return r;
+
+ hn = hostname;
+ }
+
+ return sd_dhcp_client_set_hostname(link->dhcp_client, hn);
+}
+
int dhcp4_configure(Link *link) {
int r;
@@ -605,25 +627,9 @@ int dhcp4_configure(Link *link) {
if (r < 0)
return r;
- if (link->network->dhcp_send_hostname) {
- _cleanup_free_ char *hostname = NULL;
- const char *hn = NULL;
-
- if (!link->network->dhcp_hostname) {
- hostname = gethostname_malloc();
- if (!hostname)
- return -ENOMEM;
-
- hn = hostname;
- } else
- hn = link->network->dhcp_hostname;
-
- if (!is_localhost(hn)) {
- r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
- if (r < 0)
- return r;
- }
- }
+ r = dhcp4_set_hostname(link);
+ if (r < 0)
+ return r;
if (link->network->dhcp_vendor_class_identifier) {
r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 0b634572a9..b38eec1ba7 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -851,21 +851,27 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
return 1;
}
-static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
+static int link_push_uplink_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
_cleanup_free_ struct in_addr *addresses = NULL;
size_t n_addresses = 0, n_allocated = 0;
- char **a;
+ unsigned i;
log_debug("Copying DNS server information from %s", link->ifname);
if (!link->network)
return 0;
- STRV_FOREACH(a, link->network->dns) {
+ for (i = 0; i < link->network->n_dns; i++) {
struct in_addr ia;
/* Only look for IPv4 addresses */
- if (inet_pton(AF_INET, *a, &ia) <= 0)
+ if (link->network->dns[i].family != AF_INET)
+ continue;
+
+ ia = link->network->dns[i].address.in;
+
+ /* Never propagate obviously borked data */
+ if (in4_addr_is_null(&ia) || in4_addr_is_localhost(&ia))
continue;
if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
@@ -874,8 +880,7 @@ static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
addresses[n_addresses++] = ia;
}
- if (link->network->dhcp_use_dns &&
- link->dhcp_lease) {
+ if (link->network->dhcp_use_dns && link->dhcp_lease) {
const struct in_addr *da = NULL;
int n;
@@ -896,7 +901,7 @@ static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
return sd_dhcp_server_set_dns(s, addresses, n_addresses);
}
-static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) {
+static int link_push_uplink_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) {
_cleanup_free_ struct in_addr *addresses = NULL;
size_t n_addresses = 0, n_allocated = 0;
char **a;
@@ -913,14 +918,17 @@ static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) {
if (inet_pton(AF_INET, *a, &ia) <= 0)
continue;
+ /* Never propagate obviously borked data */
+ if (in4_addr_is_null(&ia) || in4_addr_is_localhost(&ia))
+ continue;
+
if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
return log_oom();
addresses[n_addresses++] = ia;
}
- if (link->network->dhcp_use_ntp &&
- link->dhcp_lease) {
+ if (link->network->dhcp_use_ntp && link->dhcp_lease) {
const struct in_addr *da = NULL;
int n;
@@ -1034,7 +1042,7 @@ static int link_enter_set_addresses(Link *link) {
log_link_debug(link, "Not emitting DNS server information on link, couldn't find suitable uplink.");
r = 0;
} else
- r = link_push_dns_to_dhcp_server(uplink, link->dhcp_server);
+ r = link_push_uplink_dns_to_dhcp_server(uplink, link->dhcp_server);
}
if (r < 0)
log_link_warning_errno(link, r, "Failed to set DNS server for DHCP server, ignoring: %m");
@@ -1053,7 +1061,7 @@ static int link_enter_set_addresses(Link *link) {
log_link_debug(link, "Not emitting NTP server information on link, couldn't find suitable uplink.");
r = 0;
} else
- r = link_push_ntp_to_dhcp_server(uplink, link->dhcp_server);
+ r = link_push_uplink_ntp_to_dhcp_server(uplink, link->dhcp_server);
}
if (r < 0)
@@ -3235,7 +3243,7 @@ int link_save(Link *link) {
if (r < 0)
goto fail;
- fchmod(fileno(f), 0644);
+ (void) fchmod(fileno(f), 0644);
fprintf(f,
"# This is private data. Do not parse.\n"
@@ -3248,6 +3256,7 @@ int link_save(Link *link) {
sd_dhcp6_lease *dhcp6_lease = NULL;
const char *dhcp_domainname = NULL;
char **dhcp6_domains = NULL;
+ unsigned j;
if (link->dhcp6_client) {
r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
@@ -3259,7 +3268,22 @@ int link_save(Link *link) {
fputs("DNS=", f);
space = false;
- fputstrv(f, link->network->dns, NULL, &space);
+
+ for (j = 0; j < link->network->n_dns; j++) {
+ _cleanup_free_ char *b = NULL;
+
+ r = in_addr_to_string(link->network->dns[j].family,
+ &link->network->dns[j].address, &b);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to format address, ignoring: %m");
+ continue;
+ }
+
+ if (space)
+ fputc(' ', f);
+ fputs(b, f);
+ space = true;
+ }
if (link->network->dhcp_use_dns &&
link->dhcp_lease) {
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index a1252c9b51..c3d3f48a3f 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -774,11 +774,48 @@ static int manager_connect_rtnl(Manager *m) {
return 0;
}
-static int ordered_set_put_in_addr(OrderedSet *s, const struct in_addr *address) {
+static int ordered_set_put_in_addr_data(OrderedSet *s, const struct in_addr_data *address) {
char *p;
int r;
assert(s);
+ assert(address);
+
+ r = in_addr_to_string(address->family, &address->address, &p);
+ if (r < 0)
+ return r;
+
+ r = ordered_set_consume(s, p);
+ if (r == -EEXIST)
+ return 0;
+
+ return r;
+}
+
+static int ordered_set_put_in_addr_datav(OrderedSet *s, const struct in_addr_data *addresses, unsigned n) {
+ int r, c = 0;
+ unsigned i;
+
+ assert(s);
+ assert(addresses || n == 0);
+
+ for (i = 0; i < n; i++) {
+ r = ordered_set_put_in_addr_data(s, addresses+i);
+ if (r < 0)
+ return r;
+
+ c += r;
+ }
+
+ return c;
+}
+
+static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) {
+ char *p;
+ int r;
+
+ assert(s);
+ assert(address);
r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
if (r < 0)
@@ -791,14 +828,15 @@ static int ordered_set_put_in_addr(OrderedSet *s, const struct in_addr *address)
return r;
}
-static int ordered_set_put_in_addrv(OrderedSet *s, const struct in_addr *addresses, int n) {
- int r, i, c = 0;
+static int ordered_set_put_in4_addrv(OrderedSet *s, const struct in_addr *addresses, unsigned n) {
+ int r, c = 0;
+ unsigned i;
assert(s);
- assert(n <= 0 || addresses);
+ assert(n == 0 || addresses);
for (i = 0; i < n; i++) {
- r = ordered_set_put_in_addr(s, addresses+i);
+ r = ordered_set_put_in4_addr(s, addresses+i);
if (r < 0)
return r;
@@ -865,7 +903,7 @@ static int manager_save(Manager *m) {
continue;
/* First add the static configured entries */
- r = ordered_set_put_strdupv(dns, link->network->dns);
+ r = ordered_set_put_in_addr_datav(dns, link->network->dns, link->network->n_dns);
if (r < 0)
return r;
@@ -890,7 +928,7 @@ static int manager_save(Manager *m) {
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r > 0) {
- r = ordered_set_put_in_addrv(dns, addresses, r);
+ r = ordered_set_put_in4_addrv(dns, addresses, r);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
@@ -902,7 +940,7 @@ static int manager_save(Manager *m) {
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r > 0) {
- r = ordered_set_put_in_addrv(ntp, addresses, r);
+ r = ordered_set_put_in4_addrv(ntp, addresses, r);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
@@ -934,7 +972,7 @@ static int manager_save(Manager *m) {
if (r < 0)
return r;
- fchmod(fileno(f), 0644);
+ (void) fchmod(fileno(f), 0644);
fprintf(f,
"# This is private data. Do not parse.\n"
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index efd3176ac3..463f4595c1 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -54,7 +54,7 @@ Network.LLMNR, config_parse_resolve_support,
Network.MulticastDNS, config_parse_resolve_support, 0, offsetof(Network, mdns)
Network.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Network, dnssec_mode)
Network.DNSSECNegativeTrustAnchors, config_parse_dnssec_negative_trust_anchors, 0, 0
-Network.NTP, config_parse_strv, 0, offsetof(Network, ntp)
+Network.NTP, config_parse_ntp, 0, offsetof(Network, ntp)
Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward)
Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade)
Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 31e899eecd..bc4dc95ff9 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -244,7 +244,7 @@ void network_free(Network *network) {
free(network->mac);
strv_free(network->ntp);
- strv_free(network->dns);
+ free(network->dns);
strv_free(network->search_domains);
strv_free(network->route_domains);
strv_free(network->bind_carrier);
@@ -396,7 +396,7 @@ int network_apply(Network *network, Link *link) {
route->protocol = RTPROT_STATIC;
}
- if (!strv_isempty(network->dns) ||
+ if (network->n_dns > 0 ||
!strv_isempty(network->ntp) ||
!strv_isempty(network->search_domains) ||
!strv_isempty(network->route_domains))
@@ -909,13 +909,14 @@ int config_parse_dhcp_server_dns(
struct in_addr a, *m;
r = extract_first_word(&p, &w, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
return 0;
}
-
if (r == 0)
- return 0;
+ break;
if (inet_pton(AF_INET, w, &a) <= 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
@@ -929,6 +930,8 @@ int config_parse_dhcp_server_dns(
m[n->n_dhcp_server_dns++] = a;
n->dhcp_server_dns = m;
}
+
+ return 0;
}
int config_parse_dhcp_server_ntp(
@@ -956,11 +959,12 @@ int config_parse_dhcp_server_ntp(
struct in_addr a, *m;
r = extract_first_word(&p, &w, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
return 0;
}
-
if (r == 0)
return 0;
@@ -1000,29 +1004,35 @@ int config_parse_dns(
for (;;) {
_cleanup_free_ char *w = NULL;
union in_addr_union a;
+ struct in_addr_data *m;
int family;
- r = extract_first_word(&rvalue, &w, NULL, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
- if (r == 0)
- break;
+ r = extract_first_word(&rvalue, &w, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
break;
}
+ if (r == 0)
+ break;
r = in_addr_from_string_auto(w, &family, &a);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse dns server address, ignoring: %s", w);
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
continue;
}
- r = strv_consume(&n->dns, w);
- if (r < 0)
+ m = realloc(n->dns, (n->n_dns + 1) * sizeof(struct in_addr_data));
+ if (!m)
return log_oom();
- w = NULL;
+ m[n->n_dns++] = (struct in_addr_data) {
+ .family = family,
+ .address = a,
+ };
+
+ n->dns = m;
}
return 0;
@@ -1084,6 +1094,59 @@ int config_parse_dnssec_negative_trust_anchors(
return 0;
}
+int config_parse_ntp(
+ 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 ***l = data;
+ int r;
+
+ assert(l);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ *l = strv_free(*l);
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *w = NULL;
+
+ r = extract_first_word(&rvalue, &w, NULL, 0);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
+ break;
+ }
+ if (r == 0)
+ break;
+
+ r = dns_name_is_valid_or_address(w);
+ if (r <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
+ continue;
+ }
+
+ r = strv_push(l, w);
+ if (r < 0)
+ return log_oom();
+
+ w = NULL;
+ }
+
+ return 0;
+}
+
int config_parse_dhcp_route_table(const char *unit,
const char *filename,
unsigned line,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index e956a59fe3..4dbc19fc3b 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -112,19 +112,19 @@ struct Network {
DCHPClientIdentifier dhcp_client_identifier;
char *dhcp_vendor_class_identifier;
char *dhcp_hostname;
- bool dhcp_use_dns;
- bool dhcp_use_ntp;
- bool dhcp_use_mtu;
- bool dhcp_use_hostname;
- DHCPUseDomains dhcp_use_domains;
+ unsigned dhcp_route_metric;
+ uint32_t dhcp_route_table;
+ uint32_t dhcp_client_port;
bool dhcp_send_hostname;
bool dhcp_broadcast;
bool dhcp_critical;
+ bool dhcp_use_dns;
+ bool dhcp_use_ntp;
+ bool dhcp_use_mtu;
bool dhcp_use_routes;
bool dhcp_use_timezone;
- unsigned dhcp_route_metric;
- uint32_t dhcp_route_table;
- uint32_t dhcp_client_port;
+ bool dhcp_use_hostname;
+ DHCPUseDomains dhcp_use_domains;
/* DHCP Server Support */
bool dhcp_server;
@@ -174,7 +174,7 @@ struct Network {
IPv6PrivacyExtensions ipv6_privacy_extensions;
struct ether_addr *mac;
- unsigned mtu;
+ size_t mtu;
int arp;
uint32_t iaid;
DUID duid;
@@ -194,7 +194,10 @@ struct Network {
Hashmap *routes_by_section;
Hashmap *fdb_entries_by_section;
- char **search_domains, **route_domains, **dns, **ntp, **bind_carrier;
+ struct in_addr_data *dns;
+ unsigned n_dns;
+
+ char **search_domains, **route_domains, **ntp, **bind_carrier;
ResolveSupport llmnr;
ResolveSupport mdns;
@@ -233,6 +236,7 @@ int config_parse_dnssec_negative_trust_anchors(const char *unit, const char *fil
int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_lldp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dhcp_route_table(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_ntp(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);
/* Legacy IPv4LL support */
int config_parse_ipv4ll(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-mount.c b/src/nspawn/nspawn-mount.c
index 95bb3c09b0..91cb0861d3 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -298,7 +298,7 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) {
MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT|extra_flags, NULL);
}
-static int mkdir_userns(const char *path, mode_t mode, bool in_userns, uid_t uid_shift) {
+static int mkdir_userns(const char *path, mode_t mode, MountSettingsMask mask, uid_t uid_shift) {
int r;
assert(path);
@@ -307,16 +307,20 @@ static int mkdir_userns(const char *path, mode_t mode, bool in_userns, uid_t uid
if (r < 0 && errno != EEXIST)
return -errno;
- if (!in_userns) {
- r = lchown(path, uid_shift, uid_shift);
- if (r < 0)
- return -errno;
- }
+ if ((mask & MOUNT_USE_USERNS) == 0)
+ return 0;
+
+ if (mask & MOUNT_IN_USERNS)
+ return 0;
+
+ r = lchown(path, uid_shift, uid_shift);
+ if (r < 0)
+ return -errno;
return 0;
}
-static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, bool in_userns, uid_t uid_shift) {
+static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, MountSettingsMask mask, uid_t uid_shift) {
const char *p, *e;
int r;
@@ -343,12 +347,12 @@ static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, boo
if (prefix && path_startswith(prefix, t))
continue;
- r = mkdir_userns(t, mode, in_userns, uid_shift);
+ r = mkdir_userns(t, mode, mask, uid_shift);
if (r < 0)
return r;
}
- return mkdir_userns(path, mode, in_userns, uid_shift);
+ return mkdir_userns(path, mode, mask, uid_shift);
}
int mount_all(const char *dest,
@@ -422,7 +426,7 @@ int mount_all(const char *dest,
if (mount_table[k].what && r > 0)
continue;
- r = mkdir_userns_p(dest, where, 0755, in_userns, uid_shift);
+ r = mkdir_userns_p(dest, where, 0755, mount_settings, uid_shift);
if (r < 0 && r != -EEXIST) {
if (fatal)
return log_error_errno(r, "Failed to create directory %s: %m", where);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index a6adbbe879..2770770cd0 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -1143,11 +1143,6 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- if (arg_ephemeral && arg_image) {
- log_error("--ephemeral and --image= may not be combined.");
- return -EINVAL;
- }
-
if (arg_ephemeral && !IN_SET(arg_link_journal, LINK_NO, LINK_AUTO)) {
log_error("--ephemeral and --link-journal= may not be combined.");
return -EINVAL;
@@ -2605,7 +2600,7 @@ static int determine_names(void) {
r = image_find(arg_machine, &i);
if (r < 0)
return log_error_errno(r, "Failed to find image for machine '%s': %m", arg_machine);
- else if (r == 0) {
+ if (r == 0) {
log_error("No image for machine '%s': %m", arg_machine);
return -ENOENT;
}
@@ -2615,14 +2610,14 @@ static int determine_names(void) {
else
r = free_and_strdup(&arg_directory, i->path);
if (r < 0)
- return log_error_errno(r, "Invalid image directory: %m");
+ return log_oom();
if (!arg_ephemeral)
arg_read_only = arg_read_only || i->read_only;
} else
arg_directory = get_current_dir_name();
- if (!arg_directory && !arg_machine) {
+ if (!arg_directory && !arg_image) {
log_error("Failed to determine path, please use -D or -i.");
return -EINVAL;
}
@@ -2633,7 +2628,6 @@ static int determine_names(void) {
arg_machine = gethostname_malloc();
else
arg_machine = strdup(basename(arg_image ?: arg_directory));
-
if (!arg_machine)
return log_oom();
@@ -3795,7 +3789,6 @@ static int run(int master,
l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof arg_uid_shift, 0);
if (l < 0)
return log_error_errno(errno, "Failed to read UID shift: %m");
-
if (l != sizeof arg_uid_shift) {
log_error("Short read while reading UID shift.");
return -EIO;
@@ -4029,7 +4022,7 @@ static int run(int master,
terminate_machine(*pid);
/* Normally redundant, but better safe than sorry */
- kill(*pid, SIGKILL);
+ (void) kill(*pid, SIGKILL);
r = wait_for_container(*pid, &container_status);
*pid = 0;
@@ -4077,11 +4070,12 @@ int main(int argc, char *argv[]) {
_cleanup_fdset_free_ FDSet *fds = NULL;
int r, n_fd_passed, loop_nr = -1, ret = EXIT_SUCCESS;
char veth_name[IFNAMSIZ] = "";
- bool secondary = false, remove_subvol = false;
+ bool secondary = false, remove_directory = false, remove_image = false;
pid_t pid = 0;
union in_addr_union exposed = {};
_cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
- bool interactive, veth_created = false;
+ bool interactive, veth_created = false, remove_tmprootdir = false;
+ char tmprootdir[] = "/tmp/nspawn-root-XXXXXX";
log_parse_environment();
log_open();
@@ -4148,7 +4142,7 @@ int main(int argc, char *argv[]) {
else
r = tempfn_random(arg_directory, "machine.", &np);
if (r < 0) {
- log_error_errno(r, "Failed to generate name for snapshot: %m");
+ log_error_errno(r, "Failed to generate name for directory snapshot: %m");
goto finish;
}
@@ -4158,7 +4152,12 @@ int main(int argc, char *argv[]) {
goto finish;
}
- r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
+ r = btrfs_subvol_snapshot(arg_directory, np,
+ (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
+ BTRFS_SNAPSHOT_FALLBACK_COPY |
+ BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
+ BTRFS_SNAPSHOT_RECURSIVE |
+ BTRFS_SNAPSHOT_QUOTA);
if (r < 0) {
log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory);
goto finish;
@@ -4168,7 +4167,7 @@ int main(int argc, char *argv[]) {
arg_directory = np;
np = NULL;
- remove_subvol = true;
+ remove_directory = true;
} else {
r = image_path_lock(arg_directory, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
@@ -4182,7 +4181,13 @@ int main(int argc, char *argv[]) {
}
if (arg_template) {
- r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
+ r = btrfs_subvol_snapshot(arg_template, arg_directory,
+ (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
+ BTRFS_SNAPSHOT_FALLBACK_COPY |
+ BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
+ BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
+ BTRFS_SNAPSHOT_RECURSIVE |
+ BTRFS_SNAPSHOT_QUOTA);
if (r == -EEXIST) {
if (!arg_quiet)
log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
@@ -4214,28 +4219,55 @@ int main(int argc, char *argv[]) {
}
} else {
- char template[] = "/tmp/nspawn-root-XXXXXX";
-
assert(arg_image);
assert(!arg_template);
- r = image_path_lock(arg_image, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
- if (r == -EBUSY) {
- r = log_error_errno(r, "Disk image %s is currently busy.", arg_image);
- goto finish;
- }
- if (r < 0) {
- r = log_error_errno(r, "Failed to create image lock: %m");
- goto finish;
+ if (arg_ephemeral) {
+ _cleanup_free_ char *np = NULL;
+
+ r = tempfn_random(arg_image, "machine.", &np);
+ if (r < 0) {
+ log_error_errno(r, "Failed to generate name for image snapshot: %m");
+ goto finish;
+ }
+
+ r = image_path_lock(np, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
+ if (r < 0) {
+ r = log_error_errno(r, "Failed to create image lock: %m");
+ goto finish;
+ }
+
+ r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL);
+ if (r < 0) {
+ r = log_error_errno(r, "Failed to copy image file: %m");
+ goto finish;
+ }
+
+ free(arg_image);
+ arg_image = np;
+ np = NULL;
+
+ remove_image = true;
+ } else {
+ r = image_path_lock(arg_image, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
+ if (r == -EBUSY) {
+ r = log_error_errno(r, "Disk image %s is currently busy.", arg_image);
+ goto finish;
+ }
+ if (r < 0) {
+ r = log_error_errno(r, "Failed to create image lock: %m");
+ goto finish;
+ }
}
- if (!mkdtemp(template)) {
- log_error_errno(errno, "Failed to create temporary directory: %m");
- r = -errno;
+ if (!mkdtemp(tmprootdir)) {
+ r = log_error_errno(errno, "Failed to create temporary directory: %m");
goto finish;
}
- arg_directory = strdup(template);
+ remove_tmprootdir = true;
+
+ arg_directory = strdup(tmprootdir);
if (!arg_directory) {
r = log_oom();
goto finish;
@@ -4255,6 +4287,10 @@ int main(int argc, char *argv[]) {
&secondary);
if (r < 0)
goto finish;
+
+ /* Now that we mounted the image, let's try to remove it again, if it is ephemeral */
+ if (remove_image && unlink(arg_image) >= 0)
+ remove_image = false;
}
r = custom_mounts_prepare();
@@ -4321,20 +4357,35 @@ finish:
"STOPPING=1\nSTATUS=Terminating...");
if (pid > 0)
- kill(pid, SIGKILL);
+ (void) kill(pid, SIGKILL);
/* Try to flush whatever is still queued in the pty */
- if (master >= 0)
+ if (master >= 0) {
(void) copy_bytes(master, STDOUT_FILENO, (uint64_t) -1, false);
+ master = safe_close(master);
+ }
+
+ if (pid > 0)
+ (void) wait_for_terminate(pid, NULL);
loop_remove(loop_nr, &image_fd);
- if (remove_subvol && arg_directory) {
+ if (remove_directory && arg_directory) {
int k;
- k = btrfs_subvol_remove(arg_directory, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
+ k = rm_rf(arg_directory, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
if (k < 0)
- log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory);
+ log_warning_errno(k, "Cannot remove '%s', ignoring: %m", arg_directory);
+ }
+
+ if (remove_image && arg_image) {
+ if (unlink(arg_image) < 0)
+ log_warning_errno(errno, "Can't remove image file '%s', ignoring: %m", arg_image);
+ }
+
+ if (remove_tmprootdir) {
+ if (rmdir(tmprootdir) < 0)
+ log_debug_errno(errno, "Can't remove temporary root directory '%s', ignoring: %m", tmprootdir);
}
if (arg_machine) {
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index f9a6fd5f03..33debadb15 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -1324,3 +1324,15 @@ int dns_name_apply_idna(const char *name, char **ret) {
return (int) n;
}
+
+int dns_name_is_valid_or_address(const char *name) {
+ /* Returns > 0 if the specified name is either a valid IP address formatted as string or a valid DNS name */
+
+ if (isempty(name))
+ return 0;
+
+ if (in_addr_from_string_auto(name, NULL, NULL) >= 0)
+ return 1;
+
+ return dns_name_is_valid(name);
+}
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index af780f0b8b..03f160369c 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -107,3 +107,5 @@ int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b);
int dns_name_common_suffix(const char *a, const char *b, const char **ret);
int dns_name_apply_idna(const char *name, char **ret);
+
+int dns_name_is_valid_or_address(const char *name);
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index 6414ba5246..712aff65b9 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -27,18 +27,20 @@
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fs.h>
+
#include "alloc-util.h"
#include "btrfs-util.h"
#include "chattr-util.h"
#include "copy.h"
#include "dirent-util.h"
+#include "env-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "hashmap.h"
#include "lockfile-util.h"
#include "log.h"
-#include "macro.h"
#include "machine-image.h"
+#include "macro.h"
#include "mkdir.h"
#include "path-util.h"
#include "rm-rf.h"
@@ -607,14 +609,14 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
new_path = strjoina("/var/lib/machines/", new_name);
- r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
- if (r == -EOPNOTSUPP) {
- /* No btrfs snapshots supported, create a normal directory then. */
-
- r = copy_directory(i->path, new_path, false);
- if (r >= 0)
- (void) chattr_path(new_path, read_only ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
- } else if (r >= 0)
+ r = btrfs_subvol_snapshot(i->path, new_path,
+ (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
+ BTRFS_SNAPSHOT_FALLBACK_COPY |
+ BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
+ BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
+ BTRFS_SNAPSHOT_RECURSIVE |
+ BTRFS_SNAPSHOT_QUOTA);
+ if (r >= 0)
/* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
(void) btrfs_subvol_auto_qgroup(new_path, 0, true);
@@ -723,12 +725,17 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
* uses the device/inode number. This has the benefit that we
* can even lock a tree that is a mount point, correctly. */
- if (path_equal(path, "/"))
- return -EBUSY;
-
if (!path_is_absolute(path))
return -EINVAL;
+ if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
+ *local = *global = (LockFile) LOCK_FILE_INIT;
+ return 0;
+ }
+
+ if (path_equal(path, "/"))
+ return -EBUSY;
+
if (stat(path, &st) >= 0) {
if (asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
return -ENOMEM;
@@ -746,7 +753,8 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
release_lock_file(&t);
return r;
}
- }
+ } else
+ *global = (LockFile) LOCK_FILE_INIT;
*local = t;
return 0;
@@ -782,6 +790,11 @@ int image_name_lock(const char *name, int operation, LockFile *ret) {
if (!image_name_is_valid(name))
return -EINVAL;
+ if (getenv_bool("SYSTEMD_NSPAWN_LOCK") == 0) {
+ *ret = (LockFile) LOCK_FILE_INIT;
+ return 0;
+ }
+
if (streq(name, ".host"))
return -EBUSY;
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index e2f097c95e..b4db4a6702 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -627,6 +627,18 @@ static void test_dns_name_apply_idna(void) {
test_dns_name_apply_idna_one("föö.bär.", "xn--f-1gaa.xn--br-via");
}
+static void test_dns_name_is_valid_or_address(void) {
+ assert_se(dns_name_is_valid_or_address(NULL) == 0);
+ assert_se(dns_name_is_valid_or_address("") == 0);
+ assert_se(dns_name_is_valid_or_address("foobar") > 0);
+ assert_se(dns_name_is_valid_or_address("foobar.com") > 0);
+ assert_se(dns_name_is_valid_or_address("foobar..com") == 0);
+ assert_se(dns_name_is_valid_or_address("foobar.com.") > 0);
+ assert_se(dns_name_is_valid_or_address("127.0.0.1") > 0);
+ assert_se(dns_name_is_valid_or_address("::") > 0);
+ assert_se(dns_name_is_valid_or_address("::1") > 0);
+}
+
int main(int argc, char *argv[]) {
test_dns_label_unescape();
@@ -654,6 +666,7 @@ int main(int argc, char *argv[]) {
test_dns_name_compare_func();
test_dns_name_common_suffix();
test_dns_name_apply_idna();
+ test_dns_name_is_valid_or_address();
return 0;
}