chiark / gitweb /
nspawn: check with udev before we take possession of an interface
[elogind.git] / src / nspawn / nspawn.c
index 9ce1fa9b49cd72fdcf4b683ba231ccd5fd862488..abcee3fb98162fae7c7553a0e1e79f1e2d2bf9ee 100644 (file)
@@ -73,6 +73,7 @@
 #include "env-util.h"
 #include "def.h"
 #include "rtnl-util.h"
+#include "udev-util.h"
 
 typedef enum LinkJournal {
         LINK_NO,
@@ -1256,6 +1257,7 @@ static int reset_audit_loginuid(void) {
 
 static int move_network_interfaces(pid_t pid) {
         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
+        _cleanup_udev_unref_ struct udev *udev = NULL;
         char **i;
         int r;
 
@@ -1265,22 +1267,42 @@ static int move_network_interfaces(pid_t pid) {
         if (strv_isempty(arg_network_interfaces))
                 return 0;
 
-        r = sd_rtnl_open(NETLINK_ROUTE, &rtnl);
+        r = sd_rtnl_open(0, &rtnl);
         if (r < 0) {
                 log_error("Failed to connect to netlink: %s", strerror(-r));
                 return r;
         }
 
+        udev = udev_new();
+        if (!udev) {
+                log_error("Failed to connect to udev.");
+                return -ENOMEM;
+        }
+
         STRV_FOREACH(i, arg_network_interfaces) {
                 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
-                unsigned ifi;
+                _cleanup_udev_device_unref_ struct udev_device *d = NULL;
+                char ifi_str[2 + DECIMAL_STR_MAX(int)];
+                int ifi;
 
-                ifi = if_nametoindex(*i);
-                if (ifi == 0) {
+                ifi = (int) if_nametoindex(*i);
+                if (ifi <= 0) {
                         log_error("Failed to resolve interface %s: %m", *i);
                         return -errno;
                 }
 
+                sprintf(ifi_str, "n%i", ifi);
+                d = udev_device_new_from_device_id(udev, ifi_str);
+                if (!d) {
+                        log_error("Failed to get udev device for interface %s: %m", *i);
+                        return -errno;
+                }
+
+                if (udev_device_get_is_initialized(d) <= 0) {
+                        log_error("Network interface %s is not initialized yet.", *i);
+                        return -EBUSY;
+                }
+
                 r = sd_rtnl_message_new_link(RTM_NEWLINK, ifi, &m);
                 if (r < 0) {
                         log_error("Failed to allocate netlink message: %s", strerror(-r));
@@ -1295,7 +1317,7 @@ static int move_network_interfaces(pid_t pid) {
 
                 r = sd_rtnl_call(rtnl, m, 0, NULL);
                 if (r < 0) {
-                        log_error("Failed to move interface to namespace: %s", strerror(-r));
+                        log_error("Failed to move interface %s to namespace: %s", *i, strerror(-r));
                         return r;
                 }
         }