cli,devices: add device monitor
authorLubomir Rintel <lkundrak@v3.sk>
Fri, 27 Mar 2015 12:11:06 +0000 (13:11 +0100)
committerLubomir Rintel <lkundrak@v3.sk>
Sat, 5 Dec 2015 11:16:04 +0000 (12:16 +0100)
clients/cli/devices.c
clients/cli/nmcli-completion
man/nmcli.1.in

index b19657e..4cfa35c 100644 (file)
@@ -282,13 +282,14 @@ static void
 usage (void)
 {
        g_printerr (_("Usage: nmcli device { COMMAND | help }\n\n"
-                     "COMMAND := { status | show | connect | disconnect | delete | wifi | lldp }\n\n"
+                     "COMMAND := { status | show | connect | disconnect | delete | monitor | wifi | lldp }\n\n"
                      "  status\n\n"
                      "  show [<ifname>]\n\n"
                      "  set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n"
                      "  connect <ifname>\n\n"
                      "  disconnect <ifname> ...\n\n"
                      "  delete <ifname> ...\n\n"
+                     "  monitor <ifname> ...\n\n"
                      "  wifi [list [ifname <ifname>] [bssid <BSSID>]]\n\n"
                      "  wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\n"
                      "                         [bssid <BSSID>] [name <name>] [private yes|no] [hidden yes|no]\n\n"
@@ -375,6 +376,18 @@ usage_device_set (void)
                      "Modify device properties.\n\n"));
 }
 
+static void
+usage_device_monitor (void)
+{
+       g_printerr (_("Usage: nmcli device monitor { ARGUMENTS | help }\n"
+                     "\n"
+                     "ARGUMENTS := [<ifname>] ...\n"
+                     "\n"
+                     "Monitor device activity.\n"
+                     "This command prints a line whenever the specified devices change state.\n"
+                     "Monitors all devices in case no interface is specified.\n\n"));
+}
+
 static void
 usage_device_wifi (void)
 {
@@ -2062,6 +2075,97 @@ error:
        return nmc->return_value;
 }
 
+static void
+device_state (NMDevice *device, GParamSpec *pspec, NmCli *nmc)
+{
+       NMDeviceState state = nm_device_get_state (device);
+       ColorInfo color = device_state_to_color (state);
+       char *str = nmc_colorize (nmc, color.color, color.color_fmt, "%s: %s\n",
+                                 nm_device_get_iface (device),
+                                 nmc_device_state_to_string (state));
+
+       g_print ("%s", str);
+       g_free (str);
+}
+
+static void
+device_ac (NMDevice *device, GParamSpec *pspec, NmCli *nmc)
+{
+       NMActiveConnection *ac = nm_device_get_active_connection (device);
+       const char *id = ac ? nm_active_connection_get_id (ac) : NULL;
+
+       if (!id)
+               return;
+
+       g_print (_("%s: using connection '%s'\n"), nm_device_get_iface (device), id);
+}
+
+static void
+device_watch (NmCli *nmc, NMDevice *device)
+{
+       nmc->should_wait++;
+       g_signal_connect (device, "notify::" NM_DEVICE_STATE, G_CALLBACK (device_state), nmc);
+       g_signal_connect (device, "notify::" NM_DEVICE_ACTIVE_CONNECTION, G_CALLBACK (device_ac), nmc);
+}
+
+static void
+device_unwatch (NmCli *nmc, NMDevice *device)
+{
+       g_signal_handlers_disconnect_by_func (device, device_state, nmc);
+       if (g_signal_handlers_disconnect_by_func (device, device_ac, nmc))
+               nmc->should_wait--;
+
+       /* Terminate if all the watched devices disappeared. */
+       if (!nmc->should_wait)
+               quit ();
+}
+
+static void
+device_added (NMClient *client, NMDevice *device, NmCli *nmc)
+{
+       g_print (_("%s: device created\n"), nm_device_get_iface (device));
+       device_watch (nmc, NM_DEVICE (device));
+}
+
+static void
+device_removed (NMClient *client, NMDevice *device, NmCli *nmc)
+{
+       g_print (_("%s: device removed\n"), nm_device_get_iface (device));
+       device_unwatch (nmc, device);
+}
+
+static NMCResultCode
+do_device_monitor (NmCli *nmc, int argc, char **argv)
+{
+       if (argc == 0) {
+               /* No devices specified. Monitor all. */
+               const GPtrArray *devices = nm_client_get_devices (nmc->client);
+               int i;
+
+               for (i = 0; i < devices->len; i++)
+                       device_watch (nmc, g_ptr_array_index (devices, i));
+
+               /* We'll watch the device additions too, never exit. */
+               nmc->should_wait++;
+               g_signal_connect (nmc->client, NM_CLIENT_DEVICE_ADDED, G_CALLBACK (device_added), nmc);
+       } else {
+               /* Monitor just the specified devices. */
+               GSList *queue = device_list (nmc, argc, argv);
+               GSList *iter;
+
+               if (!queue)
+                       return nmc->return_value;
+
+               for (iter = queue; iter; iter = g_slist_next (iter))
+                       device_watch (nmc, NM_DEVICE (iter->data));
+               g_slist_free (queue);
+       }
+
+       g_signal_connect (nmc->client, NM_CLIENT_DEVICE_REMOVED, G_CALLBACK (device_removed), nmc);
+
+       return NMC_RESULT_SUCCESS;
+}
+
 static void
 show_access_point_info (NMDevice *device, NmCli *nmc)
 {
@@ -3510,6 +3614,13 @@ do_devices (NmCli *nmc, int argc, char **argv)
                        }
                        nmc->return_value = do_device_set (nmc, argc-1, argv+1);
                }
+               else if (matches (*argv, "monitor") == 0) {
+                       if (nmc_arg_is_help (*(argv+1))) {
+                               usage_device_monitor ();
+                               goto usage_exit;
+                       }
+                       nmc->return_value = do_device_monitor (nmc, argc-1, argv+1);
+               }
                else if (matches (*argv, "wifi") == 0) {
                        if (nmc_arg_is_help (*(argv+1))) {
                                usage_device_wifi ();
index 2424fc6..63050a3 100644 (file)
@@ -798,7 +798,7 @@ _nmcli()
             # (if the current word starts with a dash) or the OBJECT list
             # otherwise.
             if [[ "${words[0]:0:1}" != '-' ]]; then
-                OPTIONS=(help general networking radio connection device agent)
+                OPTIONS=(help general networking radio connection device agent monitor)
             elif [[ "${words[0]:1:1}" == '-' ||  "${words[0]}" == "-" ]]; then
                 OPTIONS=("${LONG_OPTIONS[@]/#/--}")
             else
@@ -870,7 +870,7 @@ _nmcli()
             ;;
         c|co|con|conn|conne|connec|connect|connecti|connectio|connection)
             if [[ ${#words[@]} -eq 2 ]]; then
-                _nmcli_compl_COMMAND "$command" show up down add modify clone edit delete reload load
+                _nmcli_compl_COMMAND "$command" show up down add modify clone edit delete monitor reload load
             elif [[ ${#words[@]} -gt 2 ]]; then
                 case "$command" in
                     s|sh|sho|show)
@@ -1280,7 +1280,8 @@ _nmcli()
                         fi
                         ;;
 
-                    de|del|dele|delet|delete)
+                    de|del|dele|delet|delete| \
+                    m|mo|mon|moni|monit|monito|monitor)
                         if [[ ${#words[@]} -eq 3 ]]; then
                             _nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
                         elif [[ ${#words[@]} -gt 3 ]]; then
@@ -1319,7 +1320,7 @@ _nmcli()
             ;;
         d|de|dev|devi|devic|device)
             if [[ ${#words[@]} -eq 2 ]]; then
-                _nmcli_compl_COMMAND "$command" status show connect disconnect delete wifi set lldp
+                _nmcli_compl_COMMAND "$command" status show connect disconnect delete monitor wifi set lldp
             elif [[ ${#words[@]} -gt 2 ]]; then
                 case "$command" in
                     s|st|sta|stat|statu|status)
@@ -1334,7 +1335,8 @@ _nmcli()
                         fi
                         ;;
                     d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect| \
-                    de|del|dele|delet|delete)
+                    de|del|dele|delet|delete| \
+                    m|mo|mon|moni|monit|monito|monitor)
                         if [[ ${#words[@]} -ge 3 ]]; then
                             _nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)"
                         fi
@@ -1408,6 +1410,8 @@ _nmcli()
                 _nmcli_compl_COMMAND "$command" secret polkit all
             fi
             ;;
+        m|mo|mon|moni|monit|monito|monitor)
+            ;;
     esac
 
     return 0
index a020ce5..fef275d 100644 (file)
@@ -799,7 +799,7 @@ of its latest state.
 .B device - show and manage network interfaces
 .br
 .TP
-.SS \fICOMMAND\fP := { status | show | set | connect | disconnect | delete | wifi | lldp }
+.SS \fICOMMAND\fP := { status | show | set | connect | disconnect | delete | monitor | wifi | lldp }
 .sp
 .RS
 .TP
@@ -843,6 +843,14 @@ Hardware devices (like Ethernet) cannot be deleted by the command.
 .br
 If '--wait' option is not specified, the default timeout will be 10 seconds.
 .TP
+.B monitor [<ifname>] ...
+.br
+Monitor device activity. This command prints a line whenever the specified devices
+change state.
+.br
+Monitors all devices in case no interface is specified. The monitor terminates when
+all specified devices disappear. 
+.TP
 .B wifi [list [ifname <ifname>] [bssid <BSSID>]]
 .br
 List available Wi\(hyFi access points. The \fIifname\fP and \fIbssid\fP options