about summary refs log tree commit diff
path: root/src/nmcli/devices.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nmcli/devices.c')
-rw-r--r--src/nmcli/devices.c214
1 files changed, 171 insertions, 43 deletions
diff --git a/src/nmcli/devices.c b/src/nmcli/devices.c
index e81e710f..2787439e 100644
--- a/src/nmcli/devices.c
+++ b/src/nmcli/devices.c
@@ -854,7 +854,8 @@ usage(void)
           "delete | monitor | wifi | lldp }\n\n"
           "  status\n\n"
           "  show [<ifname>]\n\n"
-          "  set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n"
+          "  set [ifname] <ifname> [autoconnect yes|no] [managed [--permanent|--permanent-only] "
+          "yes|no|up|down|reset]\n\n"
           "  connect <ifname>\n\n"
           "  reapply <ifname>\n\n"
           "  modify <ifname> ([+|-]<setting>.<property> <value>)+\n\n"
@@ -972,14 +973,15 @@ usage_device_delete(void)
 static void
 usage_device_set(void)
 {
-    nmc_printerr(_("Usage: nmcli device set { ARGUMENTS | help }\n"
-                   "\n"
-                   "ARGUMENTS := DEVICE { PROPERTY [ PROPERTY ... ] }\n"
-                   "DEVICE    := [ifname] <ifname> \n"
-                   "PROPERTY  := { autoconnect { yes | no } |\n"
-                   "             { managed { yes | no }\n"
-                   "\n"
-                   "Modify device properties.\n\n"));
+    nmc_printerr(_(
+        "Usage: nmcli device set { ARGUMENTS | help }\n"
+        "\n"
+        "ARGUMENTS := DEVICE { PROPERTY [ PROPERTY ... ] }\n"
+        "DEVICE    := [ifname] <ifname> \n"
+        "PROPERTY  := { autoconnect { yes | no } |\n"
+        "             { managed [--permanent | --permanent-only] { yes | no | up | down | reset }\n"
+        "\n"
+        "Modify device properties.\n\n"));
 }
 
 static void
@@ -2793,20 +2795,62 @@ do_devices_delete(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const
     }
 }
 
+typedef struct {
+    NmCli   *nmc;
+    GSource *timeout_source;
+} DeviceSetCbInfo;
+
+static void
+device_set_cb_info_finish(DeviceSetCbInfo *info)
+{
+    nm_clear_g_source_inst(&info->timeout_source);
+    g_slice_free(DeviceSetCbInfo, info);
+    quit();
+}
+
+static gboolean
+device_set_timeout_cb(gpointer user_data)
+{
+    DeviceSetCbInfo *cb_info = user_data;
+
+    timeout_cb(cb_info->nmc);
+    device_set_cb_info_finish(cb_info);
+    return G_SOURCE_REMOVE;
+}
+
+static void
+device_set_cb(GObject *object, GAsyncResult *result, gpointer user_data)
+{
+    NMDevice             *device = NM_DEVICE(object);
+    DeviceSetCbInfo      *info   = (DeviceSetCbInfo *) user_data;
+    NmCli                *nmc    = info->nmc;
+    gs_free_error GError *error  = NULL;
+
+    /* Only 'managed' is treated asynchronously, 'autoconnect' is treated synchronously */
+    if (!nm_device_set_managed_finish(device, result, &error)) {
+        g_string_printf(nmc->return_text, _("Error: set managed failed: %s."), error->message);
+        nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+    }
+
+    device_set_cb_info_finish(info);
+}
+
 static void
 do_device_set(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv)
 {
-#define DEV_SET_AUTOCONNECT 0
-#define DEV_SET_MANAGED     1
-    NMDevice *device = NULL;
-    int       i;
+    NMDevice        *device  = NULL;
+    DeviceSetCbInfo *cb_info = NULL;
+    int              i;
     struct {
         int      idx;
         gboolean value;
-    } values[2] = {
-        [DEV_SET_AUTOCONNECT] = {-1},
-        [DEV_SET_MANAGED]     = {-1},
-    };
+    } autoconnect_data = {-1};
+    struct {
+        int             idx;
+        NMDeviceManaged value;
+        guint32         flags;
+    } managed_data = {-1};
+
     gs_free_error GError *error = NULL;
 
     next_arg(nmc, &argc, &argv, NULL);
@@ -2828,49 +2872,120 @@ do_device_set(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *ar
 
     i = 0;
     do {
-        gboolean flag;
-
         if (argc == 1 && nmc->complete)
             nmc_complete_strings(*argv, "managed", "autoconnect");
 
         if (matches(*argv, "managed")) {
+            NMDeviceManaged val;
+            guint32         flags = 0;
+            gboolean        val_bool;
+            gboolean        perm = FALSE, perm_only = FALSE;
+
             argc--;
             argv++;
+
+            if (argc == 1 && nmc->complete) {
+                nmc_complete_strings(*argv,
+                                     "true",
+                                     "yes",
+                                     "on",
+                                     "false",
+                                     "no",
+                                     "off",
+                                     "up",
+                                     "down",
+                                     "reset",
+                                     "--permanent",
+                                     "--permanent-only");
+            }
+
+            if (managed_data.idx != -1) {
+                g_string_printf(nmc->return_text, _("Error: 'managed' can only be set once."));
+                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+                return;
+            }
+
+            while (argc > 0) {
+                /* --perm matches with --permanent, the most common,
+                 * but --permanent-only requires a exact match */
+                if (nm_streq0(*argv, "--permanent-only"))
+                    perm_only = TRUE;
+                else if (matches(*argv, "--permanent"))
+                    perm = TRUE;
+                else
+                    break;
+                argc--;
+                argv++;
+            }
+
+            if (perm_only && perm) {
+                g_string_printf(
+                    nmc->return_text,
+                    _("Error: '--permanent-only' and '--permanent' cannot be used together."));
+                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+                return;
+            } else if (perm) {
+                flags |= NM_DEVICE_MANAGED_FLAGS_RUNTIME | NM_DEVICE_MANAGED_FLAGS_PERMANENT;
+            } else if (perm_only) {
+                flags |= NM_DEVICE_MANAGED_FLAGS_PERMANENT;
+            } else {
+                /* If --permanent/--permanent-only are missing, set only the runtime flag, as this
+                 * is how it used to work when these options didn't exist. */
+                flags |= NM_DEVICE_MANAGED_FLAGS_RUNTIME;
+            }
+
             if (!argc) {
-                g_string_printf(nmc->return_text,
-                                _("Error: '%s' argument is missing."),
-                                *(argv - 1));
+                g_string_printf(nmc->return_text, _("Error: 'managed' argument is missing."));
                 nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
                 return;
             }
-            if (argc == 1 && nmc->complete)
-                nmc_complete_bool(*argv);
-            if (!nmc_string_to_bool(*argv, &flag, &error)) {
-                g_string_printf(nmc->return_text, _("Error: 'managed': %s."), error->message);
+
+            if (matches(*argv, "up") || matches(*argv, "down")) {
+                flags |= NM_DEVICE_MANAGED_FLAGS_SET_ADMIN_STATE;
+                val = matches(*argv, "up") ? NM_DEVICE_MANAGED_YES : NM_DEVICE_MANAGED_NO;
+            } else if (matches(*argv, "reset")) {
+                val = NM_DEVICE_MANAGED_RESET;
+            } else if (nmc_string_to_bool(*argv, &val_bool, NULL)) {
+                val = val_bool ? NM_DEVICE_MANAGED_YES : NM_DEVICE_MANAGED_NO;
+            } else {
+                g_string_printf(
+                    nmc->return_text,
+                    _("Error: 'managed': '%s' is not valid, use 'yes/no/up/down/reset'."),
+                    *argv);
                 nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
                 return;
             }
-            values[DEV_SET_MANAGED].idx   = ++i;
-            values[DEV_SET_MANAGED].value = flag;
+
+            managed_data.idx   = i++;
+            managed_data.value = val;
+            managed_data.flags = flags;
         } else if (matches(*argv, "autoconnect")) {
+            gboolean val;
+
             argc--;
             argv++;
+
             if (!argc) {
-                g_string_printf(nmc->return_text,
-                                _("Error: '%s' argument is missing."),
-                                *(argv - 1));
+                g_string_printf(nmc->return_text, _("Error: 'autoconnect' argument is missing."));
                 nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
                 return;
             }
+            if (autoconnect_data.idx != -1) {
+                g_string_printf(nmc->return_text, _("Error: 'autoconnect' can only be set once."));
+                nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+                return;
+            }
+
             if (argc == 1 && nmc->complete)
                 nmc_complete_bool(*argv);
-            if (!nmc_string_to_bool(*argv, &flag, &error)) {
+
+            if (!nmc_string_to_bool(*argv, &val, &error)) {
                 g_string_printf(nmc->return_text, _("Error: 'autoconnect': %s."), error->message);
                 nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
                 return;
             }
-            values[DEV_SET_AUTOCONNECT].idx   = ++i;
-            values[DEV_SET_AUTOCONNECT].value = flag;
+            autoconnect_data.idx   = i++;
+            autoconnect_data.value = val;
         } else {
             g_string_printf(nmc->return_text, _("Error: property '%s' is not known."), *argv);
             nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
@@ -2883,15 +2998,28 @@ do_device_set(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *ar
 
     /* when multiple properties are specified, set them in the order as they
      * are specified on the command line. */
-    if (values[DEV_SET_AUTOCONNECT].idx >= 0 && values[DEV_SET_MANAGED].idx >= 0
-        && values[DEV_SET_MANAGED].idx < values[DEV_SET_AUTOCONNECT].idx) {
-        nm_device_set_managed(device, values[DEV_SET_MANAGED].value);
-        values[DEV_SET_MANAGED].idx = -1;
-    }
-    if (values[DEV_SET_AUTOCONNECT].idx >= 0)
-        nm_device_set_autoconnect(device, values[DEV_SET_AUTOCONNECT].value);
-    if (values[DEV_SET_MANAGED].idx >= 0)
-        nm_device_set_managed(device, values[DEV_SET_MANAGED].value);
+    for (i = 0; i < 2; i++) {
+        if (autoconnect_data.idx == i) {
+            nm_device_set_autoconnect(device, autoconnect_data.value);
+        }
+        if (managed_data.idx == i) {
+            cb_info      = g_slice_new0(DeviceSetCbInfo);
+            cb_info->nmc = nmc;
+            if (nmc->timeout > 0)
+                cb_info->timeout_source =
+                    nm_g_timeout_add_seconds_source(nmc->timeout, device_set_timeout_cb, cb_info);
+
+            nmc->nowait_flag = (nmc->timeout == 0);
+            nmc->should_wait++;
+
+            nm_device_set_managed_async(device,
+                                        managed_data.value,
+                                        managed_data.flags,
+                                        NULL,
+                                        device_set_cb,
+                                        cb_info);
+        }
+    }
 }
 
 static void