merge: branch 'lr/nmcli-monitor-rh1034158'

https://bugzilla.redhat.com/show_bug.cgi?id=1034158
This commit is contained in:
Lubomir Rintel
2015-12-05 12:28:21 +01:00
15 changed files with 612 additions and 224 deletions

View File

@@ -144,7 +144,7 @@ do_agent_secret (NmCli *nmc, int argc, char **argv)
nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent"); nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent");
if (nmc->secret_agent) { if (nmc->secret_agent) {
/* We keep running */ /* We keep running */
nmc->should_wait = TRUE; nmc->should_wait++;
nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (nmc->secret_agent), NULL); nm_secret_agent_simple_enable (NM_SECRET_AGENT_SIMPLE (nmc->secret_agent), NULL);
g_signal_connect (nmc->secret_agent, "request-secrets", G_CALLBACK (secrets_requested), nmc); g_signal_connect (nmc->secret_agent, "request-secrets", G_CALLBACK (secrets_requested), nmc);
@@ -171,7 +171,7 @@ do_agent_polkit (NmCli *nmc, int argc, char **argv)
g_error_free (error); g_error_free (error);
} else { } else {
/* We keep running */ /* We keep running */
nmc->should_wait = TRUE; nmc->should_wait++;
g_print (_("nmcli successfully registered as a polkit agent.\n")); g_print (_("nmcli successfully registered as a polkit agent.\n"));
} }

View File

@@ -261,7 +261,7 @@ static void
usage (void) usage (void)
{ {
g_printerr (_("Usage: nmcli connection { COMMAND | help }\n\n" g_printerr (_("Usage: nmcli connection { COMMAND | help }\n\n"
"COMMAND := { show | up | down | add | modify | edit | delete | reload | load }\n\n" "COMMAND := { show | up | down | add | modify | edit | delete | monitor | reload | load }\n\n"
" show [--active] [--order <order spec>]\n" " show [--active] [--order <order spec>]\n"
" show [--active] [--show-secrets] [id | uuid | path | apath] <ID> ...\n\n" " show [--active] [--show-secrets] [id | uuid | path | apath] <ID> ...\n\n"
" up [[id | uuid | path] <ID>] [ifname <ifname>] [ap <BSSID>] [passwd-file <file with passwords>]\n\n" " up [[id | uuid | path] <ID>] [ifname <ifname>] [ap <BSSID>] [passwd-file <file with passwords>]\n\n"
@@ -272,6 +272,7 @@ usage (void)
" edit [id | uuid | path] <ID>\n" " edit [id | uuid | path] <ID>\n"
" edit [type <new_con_type>] [con-name <new_con_name>]\n\n" " edit [type <new_con_type>] [con-name <new_con_name>]\n\n"
" delete [id | uuid | path] <ID>\n\n" " delete [id | uuid | path] <ID>\n\n"
" monitor [id | uuid | path] <ID> ...\n\n"
" reload\n\n" " reload\n\n"
" load <filename> [ <filename>... ]\n\n")); " load <filename> [ <filename>... ]\n\n"));
} }
@@ -489,6 +490,18 @@ usage_connection_delete (void)
"The profile is identified by its name, UUID or D-Bus path.\n\n")); "The profile is identified by its name, UUID or D-Bus path.\n\n"));
} }
static void
usage_connection_monitor (void)
{
g_printerr (_("Usage: nmcli connection monitor { ARGUMENTS | help }\n"
"\n"
"ARGUMENTS := [id | uuid | path] <ID> ...\n"
"\n"
"Monitor connection profile activity.\n"
"This command prints a line whenever the specified connection changes.\n"
"Monitors all connection profiles in case none is specified.\n\n"));
}
static void static void
usage_connection_reload (void) usage_connection_reload (void)
{ {
@@ -530,6 +543,8 @@ usage_connection_second_level (const char *cmd)
usage_connection_edit (); usage_connection_edit ();
else if (matches (cmd, "delete") == 0) else if (matches (cmd, "delete") == 0)
usage_connection_delete (); usage_connection_delete ();
else if (matches (cmd, "monitor") == 0)
usage_connection_monitor ();
else if (matches (cmd, "reload") == 0) else if (matches (cmd, "reload") == 0)
usage_connection_reload (); usage_connection_reload ();
else if (matches (cmd, "load") == 0) else if (matches (cmd, "load") == 0)
@@ -1535,8 +1550,6 @@ do_connections_show (NmCli *nmc, gboolean active_only, gboolean show_secrets,
char *profile_flds = NULL, *active_flds = NULL; char *profile_flds = NULL, *active_flds = NULL;
GPtrArray *invisibles, *sorted_cons; GPtrArray *invisibles, *sorted_cons;
nmc->should_wait = FALSE;
if (argc == 0) { if (argc == 0) {
char *fields_str; char *fields_str;
char *fields_all = NMC_FIELDS_CON_SHOW_ALL; char *fields_all = NMC_FIELDS_CON_SHOW_ALL;
@@ -2377,13 +2390,14 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
* and we can follow activation progress. * and we can follow activation progress.
*/ */
nmc->nowait_flag = (nmc->timeout == 0); nmc->nowait_flag = (nmc->timeout == 0);
nmc->should_wait = TRUE; nmc->should_wait++;
if (!nmc_activate_connection (nmc, connection, ifname, ap, nsp, pwds, activate_connection_cb, &error)) { if (!nmc_activate_connection (nmc, connection, ifname, ap, nsp, pwds, activate_connection_cb, &error)) {
g_string_printf (nmc->return_text, _("Error: %s."), g_string_printf (nmc->return_text, _("Error: %s."),
error ? error->message : _("unknown error")); error ? error->message : _("unknown error"));
nmc->return_value = error ? error->code : NMC_RESULT_ERROR_CON_ACTIVATION; nmc->return_value = error ? error->code : NMC_RESULT_ERROR_CON_ACTIVATION;
g_clear_error (&error); g_clear_error (&error);
nmc->should_wait--;
goto error; goto error;
} }
@@ -2391,10 +2405,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
if (nmc->print_output == NMC_PRINT_PRETTY) if (nmc->print_output == NMC_PRINT_PRETTY)
progress_id = g_timeout_add (120, progress_cb, _("preparing")); progress_id = g_timeout_add (120, progress_cb, _("preparing"));
g_free (line);
return nmc->return_value;
error: error:
nmc->should_wait = FALSE;
g_free (line); g_free (line);
return nmc->return_value; return nmc->return_value;
} }
@@ -2549,7 +2560,7 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
queue = g_slist_reverse (queue); queue = g_slist_reverse (queue);
if (nmc->timeout > 0) { if (nmc->timeout > 0) {
nmc->should_wait = TRUE; nmc->should_wait++;
info = g_slice_new0 (ConnectionCbInfo); info = g_slice_new0 (ConnectionCbInfo);
info->nmc = nmc; info->nmc = nmc;
@@ -6586,7 +6597,7 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
goto error; goto error;
} }
nmc->should_wait = TRUE; nmc->should_wait++;
info = g_malloc0 (sizeof (AddConnectionInfo)); info = g_malloc0 (sizeof (AddConnectionInfo));
info->nmc = nmc; info->nmc = nmc;
@@ -6610,7 +6621,6 @@ error:
g_free (type_ask); g_free (type_ask);
g_free (ifname_ask); g_free (ifname_ask);
nmc->should_wait = FALSE;
return nmc->return_value; return nmc->return_value;
} }
@@ -8017,7 +8027,7 @@ property_edit_submenu (NmCli *nmc,
/* Set global variable for use in TAB completion */ /* Set global variable for use in TAB completion */
nmc_tab_completion.property = prop_name; nmc_tab_completion.property = prop_name;
prompt = nmc_colorize (nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL, prompt = nmc_colorize (nmc, nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL,
"nmcli %s.%s> ", "nmcli %s.%s> ",
nm_setting_get_name (curr_setting), prop_name); nm_setting_get_name (curr_setting), prop_name);
@@ -8345,13 +8355,14 @@ typedef struct {
} NmcEditorMenuContext; } NmcEditorMenuContext;
static void static void
menu_switch_to_level0 (NmcEditorMenuContext *menu_ctx, menu_switch_to_level0 (NmCli *nmc,
NmcEditorMenuContext *menu_ctx,
const char *prompt, const char *prompt,
NmcTermColor prompt_color) NmcTermColor prompt_color)
{ {
menu_ctx->level = 0; menu_ctx->level = 0;
g_free (menu_ctx->main_prompt); g_free (menu_ctx->main_prompt);
menu_ctx->main_prompt = nmc_colorize (prompt_color, NMC_TERM_FORMAT_NORMAL, "%s", prompt); menu_ctx->main_prompt = nmc_colorize (nmc, prompt_color, NMC_TERM_FORMAT_NORMAL, "%s", prompt);
menu_ctx->curr_setting = NULL; menu_ctx->curr_setting = NULL;
g_strfreev (menu_ctx->valid_props); g_strfreev (menu_ctx->valid_props);
menu_ctx->valid_props = NULL; menu_ctx->valid_props = NULL;
@@ -8360,14 +8371,15 @@ menu_switch_to_level0 (NmcEditorMenuContext *menu_ctx,
} }
static void static void
menu_switch_to_level1 (NmcEditorMenuContext *menu_ctx, menu_switch_to_level1 (NmCli *nmc,
NmcEditorMenuContext *menu_ctx,
NMSetting *setting, NMSetting *setting,
const char *setting_name, const char *setting_name,
NmcTermColor prompt_color) NmcTermColor prompt_color)
{ {
menu_ctx->level = 1; menu_ctx->level = 1;
g_free (menu_ctx->main_prompt); g_free (menu_ctx->main_prompt);
menu_ctx->main_prompt = nmc_colorize (prompt_color, NMC_TERM_FORMAT_NORMAL, menu_ctx->main_prompt = nmc_colorize (nmc, prompt_color, NMC_TERM_FORMAT_NORMAL,
"nmcli %s> ", setting_name); "nmcli %s> ", setting_name);
menu_ctx->curr_setting = setting; menu_ctx->curr_setting = setting;
g_strfreev (menu_ctx->valid_props); g_strfreev (menu_ctx->valid_props);
@@ -8402,7 +8414,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
g_print (_("You may edit the following settings: %s\n"), valid_settings_str); g_print (_("You may edit the following settings: %s\n"), valid_settings_str);
menu_ctx.level = 0; menu_ctx.level = 0;
menu_ctx.main_prompt = nmc_colorize (nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL, menu_ctx.main_prompt = nmc_colorize (nmc, nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL,
BASE_PROMPT); BASE_PROMPT);
menu_ctx.curr_setting = NULL; menu_ctx.curr_setting = NULL;
menu_ctx.valid_props = NULL; menu_ctx.valid_props = NULL;
@@ -8561,7 +8573,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
nmc_tab_completion.setting = setting; nmc_tab_completion.setting = setting;
/* Switch to level 1 */ /* Switch to level 1 */
menu_switch_to_level1 (&menu_ctx, setting, setting_name, nmc->editor_prompt_color); menu_switch_to_level1 (nmc, &menu_ctx, setting, setting_name, nmc->editor_prompt_color);
if (!cmd_arg_s) { if (!cmd_arg_s) {
g_print (_("You may edit the following properties: %s\n"), menu_ctx.valid_props_str); g_print (_("You may edit the following properties: %s\n"), menu_ctx.valid_props_str);
@@ -8635,7 +8647,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
connection_remove_setting (connection, ss); connection_remove_setting (connection, ss);
if (ss == menu_ctx.curr_setting) { if (ss == menu_ctx.curr_setting) {
/* If we removed the setting we are in, go up */ /* If we removed the setting we are in, go up */
menu_switch_to_level0 (&menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); menu_switch_to_level0 (nmc, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color);
nmc_tab_completion.setting = NULL; /* for TAB completion */ nmc_tab_completion.setting = NULL; /* for TAB completion */
} }
} else { } else {
@@ -8658,7 +8670,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
/* coverity[copy_paste_error] - suppress Coverity COPY_PASTE_ERROR defect */ /* coverity[copy_paste_error] - suppress Coverity COPY_PASTE_ERROR defect */
if (ss == menu_ctx.curr_setting) { if (ss == menu_ctx.curr_setting) {
/* If we removed the setting we are in, go up */ /* If we removed the setting we are in, go up */
menu_switch_to_level0 (&menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); menu_switch_to_level0 (nmc, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color);
nmc_tab_completion.setting = NULL; /* for TAB completion */ nmc_tab_completion.setting = NULL; /* for TAB completion */
} }
} else } else
@@ -8957,7 +8969,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
} }
nmc->nowait_flag = FALSE; nmc->nowait_flag = FALSE;
nmc->should_wait = TRUE; nmc->should_wait++;
nmc->print_output = NMC_PRINT_PRETTY; nmc->print_output = NMC_PRINT_PRETTY;
if (!nmc_activate_connection (nmc, NM_CONNECTION (rem_con), ifname, ap_nsp, ap_nsp, NULL, if (!nmc_activate_connection (nmc, NM_CONNECTION (rem_con), ifname, ap_nsp, ap_nsp, NULL,
activate_connection_editor_cb, &tmp_err)) { activate_connection_editor_cb, &tmp_err)) {
@@ -9000,7 +9012,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
case NMC_EDITOR_MAIN_CMD_BACK: case NMC_EDITOR_MAIN_CMD_BACK:
/* Go back (up) an the menu */ /* Go back (up) an the menu */
if (menu_ctx.level == 1) { if (menu_ctx.level == 1) {
menu_switch_to_level0 (&menu_ctx, BASE_PROMPT, nmc->editor_prompt_color); menu_switch_to_level0 (nmc, &menu_ctx, BASE_PROMPT, nmc->editor_prompt_color);
nmc_tab_completion.setting = NULL; /* for TAB completion */ nmc_tab_completion.setting = NULL; /* for TAB completion */
} }
break; break;
@@ -9046,10 +9058,10 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
nmc->editor_prompt_color = color; nmc->editor_prompt_color = color;
g_free (menu_ctx.main_prompt); g_free (menu_ctx.main_prompt);
if (menu_ctx.level == 0) if (menu_ctx.level == 0)
menu_ctx.main_prompt = nmc_colorize (nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL, menu_ctx.main_prompt = nmc_colorize (nmc, nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL,
BASE_PROMPT); BASE_PROMPT);
else else
menu_ctx.main_prompt = nmc_colorize (nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL, menu_ctx.main_prompt = nmc_colorize (nmc, nmc->editor_prompt_color, NMC_TERM_FORMAT_NORMAL,
"nmcli %s> ", "nmcli %s> ",
nm_setting_get_name (menu_ctx.curr_setting)); nm_setting_get_name (menu_ctx.curr_setting));
} }
@@ -9431,14 +9443,14 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
g_object_unref (connection); g_object_unref (connection);
g_free (nmc_tab_completion.con_type); g_free (nmc_tab_completion.con_type);
nmc->should_wait = TRUE; nmc->should_wait++;
return nmc->return_value; return nmc->return_value;
error: error:
g_assert (!connection); g_assert (!connection);
g_free (type_ask); g_free (type_ask);
nmc->should_wait = FALSE; nmc->should_wait++;
return nmc->return_value; return nmc->return_value;
} }
@@ -9481,7 +9493,6 @@ do_connection_modify (NmCli *nmc,
GError *error = NULL; GError *error = NULL;
nmc->return_value = NMC_RESULT_SUCCESS; nmc->return_value = NMC_RESULT_SUCCESS;
nmc->should_wait = FALSE;
if (argc == 0) { if (argc == 0) {
g_string_printf (nmc->return_text, _("Error: No arguments provided.")); g_string_printf (nmc->return_text, _("Error: No arguments provided."));
@@ -9536,7 +9547,7 @@ do_connection_modify (NmCli *nmc,
update_connection (!temporary, rc, modify_connection_cb, nmc); update_connection (!temporary, rc, modify_connection_cb, nmc);
nmc->should_wait = TRUE; nmc->should_wait++;
finish: finish:
return nmc->return_value; return nmc->return_value;
} }
@@ -9783,7 +9794,7 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
info->timeout_id = g_timeout_add_seconds (nmc->timeout, connection_op_timeout_cb, info); info->timeout_id = g_timeout_add_seconds (nmc->timeout, connection_op_timeout_cb, info);
nmc->nowait_flag = (nmc->timeout == 0); nmc->nowait_flag = (nmc->timeout == 0);
nmc->should_wait = TRUE; nmc->should_wait++;
g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_REMOVED, g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_REMOVED,
G_CALLBACK (connection_removed_cb), info); G_CALLBACK (connection_removed_cb), info);
@@ -9805,13 +9816,108 @@ finish:
return nmc->return_value; return nmc->return_value;
} }
static void
connection_changed (NMConnection *connection, NmCli *nmc)
{
g_print (_("%s: connection profile changed\n"), nm_connection_get_id (connection));
}
static void
connection_watch (NmCli *nmc, NMConnection *connection)
{
nmc->should_wait++;
g_signal_connect (connection, NM_CONNECTION_CHANGED, G_CALLBACK (connection_changed), nmc);
}
static void
connection_unwatch (NmCli *nmc, NMConnection *connection)
{
if (g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_changed), nmc))
nmc->should_wait--;
/* Terminate if all the watched connections disappeared. */
if (!nmc->should_wait)
quit ();
}
static void
connection_added (NMClient *client, NMRemoteConnection *con, NmCli *nmc)
{
NMConnection *connection = NM_CONNECTION (con);
g_print (_("%s: connection profile created\n"), nm_connection_get_id (connection));
connection_watch (nmc, connection);
}
static void
connection_removed (NMClient *client, NMRemoteConnection *con, NmCli *nmc)
{
NMConnection *connection = NM_CONNECTION (con);
g_print (_("%s: connection profile removed\n"), nm_connection_get_id (connection));
connection_unwatch (nmc, connection);
}
static NMCResultCode
do_connection_monitor (NmCli *nmc, int argc, char **argv)
{
if (argc == 0) {
/* No connections specified. Monitor all. */
int i;
nmc->connections = nm_client_get_connections (nmc->client);
for (i = 0; i < nmc->connections->len; i++)
connection_watch (nmc, g_ptr_array_index (nmc->connections, i));
/* We'll watch the connection additions too, never exit. */
nmc->should_wait++;
g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_ADDED, G_CALLBACK (connection_added), nmc);
} else {
/* Look up the specified connections and watch them. */
NMConnection *connection;
char **arg_ptr = argv;
int arg_num = argc;
int pos = 0;
do {
const char *selector = NULL;
if ( strcmp (*arg_ptr, "id") == 0
|| strcmp (*arg_ptr, "uuid") == 0
|| strcmp (*arg_ptr, "path") == 0) {
selector = *arg_ptr;
if (next_arg (&arg_num, &arg_ptr) != 0) {
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
return NMC_RESULT_ERROR_USER_INPUT;
}
}
connection = nmc_find_connection (nmc->connections, selector, *arg_ptr, &pos);
if (connection) {
connection_watch (nmc, connection);
} else {
g_printerr (_("Error: unknown connection '%s'\n"), *arg_ptr);
g_string_printf (nmc->return_text, _("Error: not all connections found."));
return NMC_RESULT_ERROR_NOT_FOUND;
}
/* Take next argument (if there's no other connection of the same name) */
if (!pos)
next_arg (&arg_num, &arg_ptr);
} while (arg_num > 0);
}
g_signal_connect (nmc->client, NM_CLIENT_CONNECTION_REMOVED, G_CALLBACK (connection_removed), nmc);
return NMC_RESULT_SUCCESS;
}
static NMCResultCode static NMCResultCode
do_connection_reload (NmCli *nmc, int argc, char **argv) do_connection_reload (NmCli *nmc, int argc, char **argv)
{ {
GError *error = NULL; GError *error = NULL;
nmc->return_value = NMC_RESULT_SUCCESS; nmc->return_value = NMC_RESULT_SUCCESS;
nmc->should_wait = FALSE;
if (!nm_client_reload_connections (nmc->client, NULL, &error)) { if (!nm_client_reload_connections (nmc->client, NULL, &error)) {
g_string_printf (nmc->return_text, _("Error: failed to reload connections: %s."), g_string_printf (nmc->return_text, _("Error: failed to reload connections: %s."),
@@ -9831,7 +9937,6 @@ do_connection_load (NmCli *nmc, int argc, char **argv)
int i; int i;
nmc->return_value = NMC_RESULT_SUCCESS; nmc->return_value = NMC_RESULT_SUCCESS;
nmc->should_wait = FALSE;
if (argc == 0) { if (argc == 0) {
g_string_printf (nmc->return_text, _("Error: No connection specified.")); g_string_printf (nmc->return_text, _("Error: No connection specified."));
@@ -10113,7 +10218,7 @@ do_connections (NmCli *nmc, int argc, char **argv)
} else if (matches(*argv, "add") == 0) { } else if (matches(*argv, "add") == 0) {
nmc->return_value = do_connection_add (nmc, argc-1, argv+1); nmc->return_value = do_connection_add (nmc, argc-1, argv+1);
} else if (matches(*argv, "edit") == 0) { } else if (matches(*argv, "edit") == 0) {
nmc->should_wait = TRUE; nmc->should_wait++;
editor_thread_data.nmc = nmc; editor_thread_data.nmc = nmc;
editor_thread_data.argc = argc - 1; editor_thread_data.argc = argc - 1;
editor_thread_data.argv = argv + 1; editor_thread_data.argv = argv + 1;
@@ -10121,6 +10226,8 @@ do_connections (NmCli *nmc, int argc, char **argv)
g_thread_unref (editor_thread); g_thread_unref (editor_thread);
} else if (matches(*argv, "delete") == 0) { } else if (matches(*argv, "delete") == 0) {
nmc->return_value = do_connection_delete (nmc, argc-1, argv+1); nmc->return_value = do_connection_delete (nmc, argc-1, argv+1);
} else if (matches(*argv, "monitor") == 0) {
nmc->return_value = do_connection_monitor (nmc, argc-1, argv+1);
} else if (matches(*argv, "reload") == 0) { } else if (matches(*argv, "reload") == 0) {
nmc->return_value = do_connection_reload (nmc, argc-1, argv+1); nmc->return_value = do_connection_reload (nmc, argc-1, argv+1);
} else if (matches(*argv, "load") == 0) { } else if (matches(*argv, "load") == 0) {
@@ -10158,3 +10265,9 @@ opt_error:
g_error_free (error); g_error_free (error);
return nmc->return_value; return nmc->return_value;
} }
void
monitor_connections (NmCli *nmc)
{
do_connection_monitor (nmc, 0, NULL);
}

View File

@@ -24,4 +24,6 @@
NMCResultCode do_connections (NmCli *nmc, int argc, char **argv); NMCResultCode do_connections (NmCli *nmc, int argc, char **argv);
void monitor_connections (NmCli *nmc);
#endif /* NMC_CONNECTIONS_H */ #endif /* NMC_CONNECTIONS_H */

View File

@@ -282,13 +282,14 @@ static void
usage (void) usage (void)
{ {
g_printerr (_("Usage: nmcli device { COMMAND | help }\n\n" 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" " status\n\n"
" show [<ifname>]\n\n" " show [<ifname>]\n\n"
" set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n" " set [ifname] <ifname> [autoconnect yes|no] [managed yes|no]\n\n"
" connect <ifname>\n\n" " connect <ifname>\n\n"
" disconnect <ifname> ...\n\n" " disconnect <ifname> ...\n\n"
" delete <ifname> ...\n\n" " delete <ifname> ...\n\n"
" monitor <ifname> ...\n\n"
" wifi [list [ifname <ifname>] [bssid <BSSID>]]\n\n" " wifi [list [ifname <ifname>] [bssid <BSSID>]]\n\n"
" wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>]\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" " [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")); "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 static void
usage_device_wifi (void) usage_device_wifi (void)
{ {
@@ -484,6 +497,63 @@ get_devices_sorted (NMClient *client)
return sorted; return sorted;
} }
static GSList *
device_list (NmCli *nmc, int argc, char **argv)
{
int arg_num = argc;
char **arg_arr = NULL;
char **arg_ptr = argv;
NMDevice **devices;
GSList *queue = NULL;
NMDevice *device;
int i;
if (argc == 0) {
if (nmc->ask) {
char *line = nmc_readline (PROMPT_INTERFACES);
nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num);
g_free (line);
arg_ptr = arg_arr;
}
if (arg_num == 0) {
g_string_printf (nmc->return_text, _("Error: No interface specified."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
}
devices = get_devices_sorted (nmc->client);
while (arg_num > 0) {
device = NULL;
for (i = 0; devices[i]; i++) {
if (!g_strcmp0 (nm_device_get_iface (devices[i]), *arg_ptr)) {
device = devices[i];
break;
}
}
if (device) {
if (!g_slist_find (queue, device))
queue = g_slist_prepend (queue, device);
else
g_printerr (_("Warning: argument '%s' is duplicated.\n"), *arg_ptr);
} else {
g_printerr (_("Error: Device '%s' not found.\n"), *arg_ptr);
g_string_printf (nmc->return_text, _("Error: not all devices found."));
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
}
/* Take next argument */
next_arg (&arg_num, &arg_ptr);
}
g_free (devices);
error:
g_strfreev (arg_arr);
return queue;
}
static int static int
compare_aps (gconstpointer a, gconstpointer b, gpointer user_data) compare_aps (gconstpointer a, gconstpointer b, gpointer user_data)
{ {
@@ -1184,11 +1254,28 @@ show_device_info (NMDevice *device, NmCli *nmc)
return TRUE; return TRUE;
} }
static ColorInfo
device_state_to_color (NMDeviceState state)
{
ColorInfo color_info = { NMC_TERM_COLOR_NORMAL, NMC_TERM_FORMAT_NORMAL };
if (state <= NM_DEVICE_STATE_UNAVAILABLE)
color_info.color_fmt= NMC_TERM_FORMAT_DIM;
else if (state == NM_DEVICE_STATE_DISCONNECTED)
color_info.color = NMC_TERM_COLOR_RED;
else if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES)
color_info.color = NMC_TERM_COLOR_YELLOW;
else if (state == NM_DEVICE_STATE_ACTIVATED)
color_info.color = NMC_TERM_COLOR_GREEN;
return color_info;
}
static void static void
fill_output_device_status (NMDevice *device, NmCli *nmc) fill_output_device_status (NMDevice *device, NmCli *nmc)
{ {
NMActiveConnection *ac; NMActiveConnection *ac;
NMDeviceState state; NMDeviceState state;
ColorInfo color_info;
NmcOutputField *arr = nmc_dup_fields_array (nmc_fields_dev_status, NmcOutputField *arr = nmc_dup_fields_array (nmc_fields_dev_status,
sizeof (nmc_fields_dev_status), sizeof (nmc_fields_dev_status),
0); 0);
@@ -1197,14 +1284,9 @@ fill_output_device_status (NMDevice *device, NmCli *nmc)
ac = nm_device_get_active_connection (device); ac = nm_device_get_active_connection (device);
/* Show devices in color */ /* Show devices in color */
if (state <= NM_DEVICE_STATE_UNAVAILABLE) color_info = device_state_to_color (state);
set_val_color_fmt_all (arr, NMC_TERM_FORMAT_DIM); set_val_color_all (arr, color_info.color);
else if (state == NM_DEVICE_STATE_DISCONNECTED) set_val_color_fmt_all (arr, color_info.color_fmt);
set_val_color_all (arr, NMC_TERM_COLOR_RED);
else if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES)
set_val_color_all (arr, NMC_TERM_COLOR_YELLOW);
else if (state == NM_DEVICE_STATE_ACTIVATED)
set_val_color_all (arr, NMC_TERM_COLOR_GREEN);
set_val_strc (arr, 0, nm_device_get_iface (device)); set_val_strc (arr, 0, nm_device_get_iface (device));
set_val_strc (arr, 1, nm_device_get_type_description (device)); set_val_strc (arr, 1, nm_device_get_type_description (device));
@@ -1622,7 +1704,7 @@ do_device_connect (NmCli *nmc, int argc, char **argv)
* till connect_device_cb() is called, giving NM time to check our permissions. * till connect_device_cb() is called, giving NM time to check our permissions.
*/ */
nmc->nowait_flag = (nmc->timeout == 0); nmc->nowait_flag = (nmc->timeout == 0);
nmc->should_wait = TRUE; nmc->should_wait++;
/* Create secret agent */ /* Create secret agent */
nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-connect"); nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-connect");
@@ -1770,64 +1852,17 @@ disconnect_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
static NMCResultCode static NMCResultCode
do_device_disconnect (NmCli *nmc, int argc, char **argv) do_device_disconnect (NmCli *nmc, int argc, char **argv)
{ {
NMDevice **devices;
NMDevice *device; NMDevice *device;
DeviceCbInfo *info = NULL; DeviceCbInfo *info = NULL;
GSList *queue = NULL, *iter; GSList *queue, *iter;
char **arg_arr = NULL;
char **arg_ptr = argv;
int arg_num = argc;
int i;
/* Set default timeout for disconnect operation. */ /* Set default timeout for disconnect operation. */
if (nmc->timeout == -1) if (nmc->timeout == -1)
nmc->timeout = 10; nmc->timeout = 10;
if (argc == 0) { queue = device_list (nmc, argc, argv);
if (nmc->ask) { if (!queue)
char *line = nmc_readline (PROMPT_INTERFACES);
nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num);
g_free (line);
arg_ptr = arg_arr;
}
if (arg_num == 0) {
g_string_printf (nmc->return_text, _("Error: No interface specified."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error; goto error;
}
}
devices = get_devices_sorted (nmc->client);
while (arg_num > 0) {
device = NULL;
for (i = 0; devices[i]; i++) {
if (!g_strcmp0 (nm_device_get_iface (devices[i]), *arg_ptr)) {
device = devices[i];
break;
}
}
if (device) {
if (!g_slist_find (queue, device))
queue = g_slist_prepend (queue, device);
else
g_printerr (_("Warning: argument '%s' is duplicated.\n"), *arg_ptr);
} else {
g_printerr (_("Error: Device '%s' not found.\n"), *arg_ptr);
g_string_printf (nmc->return_text, _("Error: not all devices found."));
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
}
/* Take next argument */
next_arg (&arg_num, &arg_ptr);
}
g_free (devices);
if (!queue) {
g_string_printf (nmc->return_text, _("Error: no valid device provided."));
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
goto error;
}
queue = g_slist_reverse (queue); queue = g_slist_reverse (queue);
info = g_slice_new0 (DeviceCbInfo); info = g_slice_new0 (DeviceCbInfo);
@@ -1840,7 +1875,7 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv)
G_CALLBACK (device_removed_cb), info); G_CALLBACK (device_removed_cb), info);
nmc->nowait_flag = (nmc->timeout == 0); nmc->nowait_flag = (nmc->timeout == 0);
nmc->should_wait = TRUE; nmc->should_wait++;
for (iter = queue; iter; iter = g_slist_next (iter)) { for (iter = queue; iter; iter = g_slist_next (iter)) {
device = iter->data; device = iter->data;
@@ -1854,7 +1889,6 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv)
} }
error: error:
g_strfreev (arg_arr);
g_slist_free (queue); g_slist_free (queue);
return nmc->return_value; return nmc->return_value;
} }
@@ -1885,71 +1919,17 @@ delete_device_cb (GObject *object, GAsyncResult *result, gpointer user_data)
static NMCResultCode static NMCResultCode
do_device_delete (NmCli *nmc, int argc, char **argv) do_device_delete (NmCli *nmc, int argc, char **argv)
{ {
NMDevice **devices;
NMDevice *device; NMDevice *device;
DeviceCbInfo *info = NULL; DeviceCbInfo *info = NULL;
GSList *queue = NULL, *iter; GSList *queue, *iter;
char **arg_arr = NULL;
char **arg_ptr = argv;
int arg_num = argc;
int i;
/* Set default timeout for delete operation. */ /* Set default timeout for delete operation. */
if (nmc->timeout == -1) if (nmc->timeout == -1)
nmc->timeout = 10; nmc->timeout = 10;
if (argc == 0) { queue = device_list (nmc, argc, argv);
if (nmc->ask) { if (!queue)
char *line = nmc_readline (PROMPT_INTERFACES);
nmc_string_to_arg_array (line, NULL, FALSE, &arg_arr, &arg_num);
g_free (line);
arg_ptr = arg_arr;
}
if (arg_num == 0) {
g_string_printf (nmc->return_text, _("Error: No interface specified."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error; goto error;
}
}
devices = get_devices_sorted (nmc->client);
while (arg_num > 0) {
device = NULL;
for (i = 0; devices[i]; i++) {
if (!g_strcmp0 (nm_device_get_iface (devices[i]), *arg_ptr)) {
device = devices[i];
break;
}
}
if (device) {
if (!g_slist_find (queue, device)) {
if (nm_device_is_software (device))
queue = g_slist_prepend (queue, device);
else {
g_printerr (_("Error: Device '%s' is a hardware device. It can't be deleted.\n"),
*arg_ptr);
g_string_printf (nmc->return_text, _("Error: not all devices valid."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
}
} else
g_printerr (_("Warning: argument '%s' is duplicated.\n"), *arg_ptr);
} else {
g_printerr (_("Error: Device '%s' not found.\n"), *arg_ptr);
g_string_printf (nmc->return_text, _("Error: not all devices found."));
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
}
/* Take next argument */
next_arg (&arg_num, &arg_ptr);
}
g_free (devices);
if (!queue) {
g_string_printf (nmc->return_text, _("Error: no valid device provided."));
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
goto error;
}
queue = g_slist_reverse (queue); queue = g_slist_reverse (queue);
info = g_slice_new0 (DeviceCbInfo); info = g_slice_new0 (DeviceCbInfo);
@@ -1961,7 +1941,7 @@ do_device_delete (NmCli *nmc, int argc, char **argv)
G_CALLBACK (device_removed_cb), info); G_CALLBACK (device_removed_cb), info);
nmc->nowait_flag = (nmc->timeout == 0); nmc->nowait_flag = (nmc->timeout == 0);
nmc->should_wait = TRUE; nmc->should_wait++;
for (iter = queue; iter; iter = g_slist_next (iter)) { for (iter = queue; iter; iter = g_slist_next (iter)) {
device = iter->data; device = iter->data;
@@ -1973,7 +1953,6 @@ do_device_delete (NmCli *nmc, int argc, char **argv)
} }
error: error:
g_strfreev (arg_arr);
g_slist_free (queue); g_slist_free (queue);
return nmc->return_value; return nmc->return_value;
} }
@@ -2096,6 +2075,97 @@ error:
return nmc->return_value; 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 static void
show_access_point_info (NMDevice *device, NmCli *nmc) show_access_point_info (NMDevice *device, NmCli *nmc)
{ {
@@ -2726,7 +2796,7 @@ do_device_wifi_connect_network (NmCli *nmc, int argc, char **argv)
* the user doesn't want to wait, in order to give NM time to check our * the user doesn't want to wait, in order to give NM time to check our
* permissions. */ * permissions. */
nmc->nowait_flag = (nmc->timeout == 0); nmc->nowait_flag = (nmc->timeout == 0);
nmc->should_wait = TRUE; nmc->should_wait++;
info = g_malloc0 (sizeof (AddAndActivateInfo)); info = g_malloc0 (sizeof (AddAndActivateInfo));
info->nmc = nmc; info->nmc = nmc;
@@ -3116,8 +3186,6 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
const char *ssid; const char *ssid;
int i; int i;
nmc->should_wait = TRUE;
ssids = g_ptr_array_new (); ssids = g_ptr_array_new ();
/* Get the parameters */ /* Get the parameters */
@@ -3185,7 +3253,7 @@ do_device_wifi_rescan (NmCli *nmc, int argc, char **argv)
g_ptr_array_free (ssids, FALSE); g_ptr_array_free (ssids, FALSE);
return nmc->return_value; return nmc->return_value;
error: error:
nmc->should_wait = FALSE; nmc->should_wait++;
g_ptr_array_free (ssids, FALSE); g_ptr_array_free (ssids, FALSE);
return nmc->return_value; return nmc->return_value;
} }
@@ -3546,6 +3614,13 @@ do_devices (NmCli *nmc, int argc, char **argv)
} }
nmc->return_value = do_device_set (nmc, argc-1, argv+1); 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) { else if (matches (*argv, "wifi") == 0) {
if (nmc_arg_is_help (*(argv+1))) { if (nmc_arg_is_help (*(argv+1))) {
usage_device_wifi (); usage_device_wifi ();
@@ -3582,3 +3657,9 @@ opt_error:
g_error_free (error); g_error_free (error);
return nmc->return_value; return nmc->return_value;
} }
void
monitor_devices (NmCli *nmc)
{
do_device_monitor (nmc, 0, NULL);
}

View File

@@ -24,4 +24,6 @@
NMCResultCode do_devices (NmCli *nmc, int argc, char **argv); NMCResultCode do_devices (NmCli *nmc, int argc, char **argv);
void monitor_devices (NmCli *nmc);
#endif /* NMC_DEVICES_H */ #endif /* NMC_DEVICES_H */

View File

@@ -27,6 +27,9 @@
#include "utils.h" #include "utils.h"
#include "general.h" #include "general.h"
#include "devices.h"
#include "connections.h"
/* Available fields for 'general status' */ /* Available fields for 'general status' */
static NmcOutputField nmc_fields_nm_status[] = { static NmcOutputField nmc_fields_nm_status[] = {
{"RUNNING", N_("RUNNING")}, /* 0 */ {"RUNNING", N_("RUNNING")}, /* 0 */
@@ -207,6 +210,15 @@ usage_radio_wwan (void)
"Get status of mobile broadband radio switch, or turn it on/off.\n\n")); "Get status of mobile broadband radio switch, or turn it on/off.\n\n"));
} }
static void
usage_monitor (void)
{
g_printerr (_("Usage: nmcli monitor\n"
"\n"
"Monitor NetworkManager changes.\n"
"Prints a line whenever a change occurs in NetworkManager\n\n"));
}
/* quit main loop */ /* quit main loop */
static void static void
quit (void) quit (void)
@@ -619,7 +631,7 @@ do_general (NmCli *nmc, int argc, char **argv)
if (next_arg (&argc, &argv) == 0) if (next_arg (&argc, &argv) == 0)
g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname); g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname);
nmc->should_wait = TRUE; nmc->should_wait++;
nmc->get_client (nmc); /* create NMClient */ nmc->get_client (nmc); /* create NMClient */
nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc); nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc);
} }
@@ -889,3 +901,88 @@ finish:
return nmc->return_value; return nmc->return_value;
} }
static void
client_hostname (NMClient *client, GParamSpec *param, NmCli *nmc)
{
const char *hostname;
g_object_get (client, NM_CLIENT_HOSTNAME, &hostname, NULL);
g_print (_("Hostname set to '%s'\n"), hostname);
}
static void
client_primary_connection (NMClient *client, GParamSpec *param, NmCli *nmc)
{
NMConnection *primary;
const char *id;
g_object_get (client, NM_CLIENT_PRIMARY_CONNECTION, &primary, NULL);
if (primary) {
id = nm_connection_get_id (primary);
if (!id)
id = nm_connection_get_uuid (primary);
g_print (_("'%s' is now the primary connection\n"), id);
} else {
g_print (_("There's no primary connection\n"));
}
}
static void
client_connectivity (NMClient *client, GParamSpec *param, NmCli *nmc)
{
NMConnectivityState connectivity;
char *str;
g_object_get (client, NM_CLIENT_CONNECTIVITY, &connectivity, NULL);
str = nmc_colorize (nmc, connectivity_to_color (connectivity), NMC_TERM_FORMAT_NORMAL,
_("Connectivity is now '%s'\n"), nm_connectivity_to_string (connectivity));
g_print ("%s", str);
g_free (str);
}
static void
client_state (NMClient *client, GParamSpec *param, NmCli *nmc)
{
NMState state;
char *str;
g_object_get (client, NM_CLIENT_STATE, &state, NULL);
str = nmc_colorize (nmc, state_to_color (state), NMC_TERM_FORMAT_NORMAL,
_("Networkmanager is now in the '%s' state\n"),
nm_state_to_string (state));
g_print ("%s", str);
g_free (str);
}
NMCResultCode
do_monitor (NmCli *nmc, int argc, char **argv)
{
if (argc > 0) {
if (!nmc_arg_is_help (*argv)) {
g_string_printf (nmc->return_text, _("Error: 'monitor' command '%s' is not valid."), *argv);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
}
usage_monitor ();
return nmc->return_value;
}
nmc->get_client (nmc); /* create NMClient */
g_signal_connect (nmc->client, "notify::" NM_CLIENT_HOSTNAME,
G_CALLBACK (client_hostname), nmc);
g_signal_connect (nmc->client, "notify::" NM_CLIENT_PRIMARY_CONNECTION,
G_CALLBACK (client_primary_connection), nmc);
g_signal_connect (nmc->client, "notify::" NM_CLIENT_CONNECTIVITY,
G_CALLBACK (client_connectivity), nmc);
g_signal_connect (nmc->client, "notify::" NM_CLIENT_STATE,
G_CALLBACK (client_state), nmc);
nmc->should_wait++;
monitor_devices (nmc);
monitor_connections (nmc);
return NMC_RESULT_SUCCESS;
}

View File

@@ -25,5 +25,6 @@
NMCResultCode do_general (NmCli *nmc, int argc, char **argv); NMCResultCode do_general (NmCli *nmc, int argc, char **argv);
NMCResultCode do_networking (NmCli *nmc, int argc, char **argv); NMCResultCode do_networking (NmCli *nmc, int argc, char **argv);
NMCResultCode do_radio (NmCli *nmc, int argc, char **argv); NMCResultCode do_radio (NmCli *nmc, int argc, char **argv);
NMCResultCode do_monitor (NmCli *nmc, int argc, char **argv);
#endif /* NMC_GENERAL_H */ #endif /* NMC_GENERAL_H */

View File

@@ -798,7 +798,7 @@ _nmcli()
# (if the current word starts with a dash) or the OBJECT list # (if the current word starts with a dash) or the OBJECT list
# otherwise. # otherwise.
if [[ "${words[0]:0:1}" != '-' ]]; then 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 elif [[ "${words[0]:1:1}" == '-' || "${words[0]}" == "-" ]]; then
OPTIONS=("${LONG_OPTIONS[@]/#/--}") OPTIONS=("${LONG_OPTIONS[@]/#/--}")
else else
@@ -870,7 +870,7 @@ _nmcli()
;; ;;
c|co|con|conn|conne|connec|connect|connecti|connectio|connection) c|co|con|conn|conne|connec|connect|connecti|connectio|connection)
if [[ ${#words[@]} -eq 2 ]]; then 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 elif [[ ${#words[@]} -gt 2 ]]; then
case "$command" in case "$command" in
s|sh|sho|show) s|sh|sho|show)
@@ -1280,7 +1280,8 @@ _nmcli()
fi fi
;; ;;
de|del|dele|delet|delete) de|del|dele|delet|delete| \
m|mo|mon|moni|monit|monito|monitor)
if [[ ${#words[@]} -eq 3 ]]; then if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")" _nmcli_compl_COMMAND_nl "${words[2]}" "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_show NAME)")"
elif [[ ${#words[@]} -gt 3 ]]; then elif [[ ${#words[@]} -gt 3 ]]; then
@@ -1319,7 +1320,7 @@ _nmcli()
;; ;;
d|de|dev|devi|devic|device) d|de|dev|devi|devic|device)
if [[ ${#words[@]} -eq 2 ]]; then 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 elif [[ ${#words[@]} -gt 2 ]]; then
case "$command" in case "$command" in
s|st|sta|stat|statu|status) s|st|sta|stat|statu|status)
@@ -1334,7 +1335,8 @@ _nmcli()
fi fi
;; ;;
d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect| \ 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 if [[ ${#words[@]} -ge 3 ]]; then
_nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)" _nmcli_compl_COMMAND_nl "${words[2]}" "$(_nmcli_dev_status DEVICE)"
fi fi
@@ -1408,6 +1410,8 @@ _nmcli()
_nmcli_compl_COMMAND "$command" secret polkit all _nmcli_compl_COMMAND "$command" secret polkit all
fi fi
;; ;;
m|mo|mon|moni|monit|monito|monitor)
;;
esac esac
return 0 return 0

View File

@@ -103,6 +103,7 @@ usage (const char *prog_name)
" c[onnection] NetworkManager's connections\n" " c[onnection] NetworkManager's connections\n"
" d[evice] devices managed by NetworkManager\n" " d[evice] devices managed by NetworkManager\n"
" a[gent] NetworkManager secret agent or polkit agent\n" " a[gent] NetworkManager secret agent or polkit agent\n"
" m[monitor] monitor NetworkManager changes\n"
"\n"), "\n"),
prog_name); prog_name);
} }
@@ -119,6 +120,7 @@ static const struct cmd {
NMCResultCode (*func) (NmCli *nmc, int argc, char **argv); NMCResultCode (*func) (NmCli *nmc, int argc, char **argv);
} nmcli_cmds[] = { } nmcli_cmds[] = {
{ "general", do_general }, { "general", do_general },
{ "monitor", do_monitor },
{ "networking", do_networking }, { "networking", do_networking },
{ "radio", do_radio }, { "radio", do_radio },
{ "connection", do_connections }, { "connection", do_connections },
@@ -532,7 +534,7 @@ nmc_init (NmCli *nmc)
nmc->pwds_hash = NULL; nmc->pwds_hash = NULL;
nmc->pk_listener = NULL; nmc->pk_listener = NULL;
nmc->should_wait = FALSE; nmc->should_wait = 0;
nmc->nowait_flag = TRUE; nmc->nowait_flag = TRUE;
nmc->print_output = NMC_PRINT_NORMAL; nmc->print_output = NMC_PRINT_NORMAL;
nmc->multiline_output = FALSE; nmc->multiline_output = FALSE;

View File

@@ -144,7 +144,7 @@ typedef struct _NmCli {
GHashTable *pwds_hash; /* Hash table with passwords in passwd-file */ GHashTable *pwds_hash; /* Hash table with passwords in passwd-file */
NMPolkitListener *pk_listener ; /* polkit agent listener */ NMPolkitListener *pk_listener ; /* polkit agent listener */
gboolean should_wait; /* Indication that nmcli should not end yet */ int should_wait; /* Semaphore indicating whether nmcli should not end or not yet */
gboolean nowait_flag; /* '--nowait' option; used for passing to callbacks */ gboolean nowait_flag; /* '--nowait' option; used for passing to callbacks */
NMCPrintOutput print_output; /* Output mode */ NMCPrintOutput print_output; /* Output mode */
gboolean multiline_output; /* Multiline output instead of default tabular */ gboolean multiline_output; /* Multiline output instead of default tabular */

View File

@@ -356,8 +356,20 @@ nmc_term_format_sequence (NmcTermFormat format)
} }
} }
static gboolean
use_colors (NmCli *nmc)
{
if (nmc == NULL)
return FALSE;
if (nmc->use_colors == NMC_USE_COLOR_AUTO)
nmc->use_colors = isatty (fileno (stdout)) ? NMC_USE_COLOR_YES : NMC_USE_COLOR_NO;
return nmc->use_colors == NMC_USE_COLOR_YES;
}
char * char *
nmc_colorize (NmcTermColor color, NmcTermFormat format, const char *fmt, ...) nmc_colorize (NmCli *nmc, NmcTermColor color, NmcTermFormat format, const char *fmt, ...)
{ {
va_list args; va_list args;
char *str, *colored; char *str, *colored;
@@ -368,6 +380,9 @@ nmc_colorize (NmcTermColor color, NmcTermFormat format, const char *fmt, ...)
str = g_strdup_vprintf (fmt, args); str = g_strdup_vprintf (fmt, args);
va_end (args); va_end (args);
if (!use_colors (nmc))
return str;
ansi_color = nmc_term_color_sequence (color); ansi_color = nmc_term_color_sequence (color);
ansi_fmt = nmc_term_format_sequence (format); ansi_fmt = nmc_term_format_sequence (format);
color_end = *ansi_color ? end_seq : ""; color_end = *ansi_color ? end_seq : "";
@@ -1047,7 +1062,7 @@ nmc_empty_output_fields (NmCli *nmc)
} }
static char * static char *
colorize_string (gboolean colorize, colorize_string (NmCli *nmc,
NmcTermColor color, NmcTermColor color,
NmcTermFormat color_fmt, NmcTermFormat color_fmt,
const char *str, const char *str,
@@ -1055,9 +1070,9 @@ colorize_string (gboolean colorize,
{ {
char *out; char *out;
if ( colorize if ( use_colors (nmc)
&& (color != NMC_TERM_COLOR_NORMAL || color_fmt != NMC_TERM_FORMAT_NORMAL)) { && (color != NMC_TERM_COLOR_NORMAL || color_fmt != NMC_TERM_FORMAT_NORMAL)) {
out = nmc_colorize (color, color_fmt, str); out = nmc_colorize (nmc, color, color_fmt, str);
*dealloc = TRUE; *dealloc = TRUE;
} else { } else {
out = (char *) str; out = (char *) str;
@@ -1067,11 +1082,11 @@ colorize_string (gboolean colorize,
} }
static char * static char *
get_value_to_print (NmcOutputField *field, get_value_to_print (NmCli *nmc,
NmcOutputField *field,
gboolean field_name, gboolean field_name,
const char *not_set_str, const char *not_set_str,
gboolean *dealloc, gboolean *dealloc)
gboolean colorize)
{ {
gboolean is_array = field->value_is_array; gboolean is_array = field->value_is_array;
char *value, *out; char *value, *out;
@@ -1087,7 +1102,7 @@ get_value_to_print (NmcOutputField *field,
free_value = field->value && is_array && !field_name; free_value = field->value && is_array && !field_name;
/* colorize the value */ /* colorize the value */
out = colorize_string (colorize, field->color, field->color_fmt, value, &free_out); out = colorize_string (nmc, field->color, field->color_fmt, value, &free_out);
if (free_out) { if (free_out) {
if (free_value) if (free_value)
g_free (value); g_free (value);
@@ -1125,7 +1140,6 @@ print_required_fields (NmCli *nmc, const NmcOutputField field_values[])
gboolean field_names = field_values[0].flags & NMC_OF_FLAG_FIELD_NAMES; gboolean field_names = field_values[0].flags & NMC_OF_FLAG_FIELD_NAMES;
gboolean section_prefix = field_values[0].flags & NMC_OF_FLAG_SECTION_PREFIX; gboolean section_prefix = field_values[0].flags & NMC_OF_FLAG_SECTION_PREFIX;
gboolean main_header = main_header_add || main_header_only; gboolean main_header = main_header_add || main_header_only;
gboolean colorize;
/* No headers are printed in terse mode: /* No headers are printed in terse mode:
* - neither main header nor field (column) names * - neither main header nor field (column) names
@@ -1133,11 +1147,6 @@ print_required_fields (NmCli *nmc, const NmcOutputField field_values[])
if ((main_header_only || field_names) && terse) if ((main_header_only || field_names) && terse)
return; return;
/* Only show colors if the output is a terminal */
colorize = nmc->use_colors == NMC_USE_COLOR_YES ? TRUE :
nmc->use_colors == NMC_USE_COLOR_NO ? FALSE :
isatty (fileno (stdout));
if (multiline) { if (multiline) {
/* --- Multiline mode --- */ /* --- Multiline mode --- */
enum { ML_HEADER_WIDTH = 79 }; enum { ML_HEADER_WIDTH = 79 };
@@ -1178,7 +1187,7 @@ print_required_fields (NmCli *nmc, const NmcOutputField field_values[])
for (p = (const char **) field_values[idx].value, j = 1; p && *p; p++, j++) { for (p = (const char **) field_values[idx].value, j = 1; p && *p; p++, j++) {
val = *p ? *p : not_set_str; val = *p ? *p : not_set_str;
print_val = colorize_string (colorize, field_values[idx].color, field_values[idx].color_fmt, print_val = colorize_string (nmc, field_values[idx].color, field_values[idx].color_fmt,
val, &free_print_val); val, &free_print_val);
tmp = g_strdup_printf ("%s%s%s[%d]:", tmp = g_strdup_printf ("%s%s%s[%d]:",
section_prefix ? (const char*) field_values[0].value : "", section_prefix ? (const char*) field_values[0].value : "",
@@ -1199,7 +1208,7 @@ print_required_fields (NmCli *nmc, const NmcOutputField field_values[])
char *print_val; char *print_val;
val = val ? val : not_set_str; val = val ? val : not_set_str;
print_val = colorize_string (colorize, field_values[idx].color, field_values[idx].color_fmt, print_val = colorize_string (nmc, field_values[idx].color, field_values[idx].color_fmt,
val, &free_print_val); val, &free_print_val);
tmp = g_strdup_printf ("%s%s%s:", tmp = g_strdup_printf ("%s%s%s:",
section_prefix ? hdr_name : "", section_prefix ? hdr_name : "",
@@ -1228,8 +1237,8 @@ print_required_fields (NmCli *nmc, const NmcOutputField field_values[])
for (i = 0; i < fields.indices->len; i++) { for (i = 0; i < fields.indices->len; i++) {
int idx = g_array_index (fields.indices, int, i); int idx = g_array_index (fields.indices, int, i);
gboolean dealloc; gboolean dealloc;
char *value = get_value_to_print ((NmcOutputField *) field_values+idx, field_names, char *value = get_value_to_print (nmc, (NmcOutputField *) field_values+idx, field_names,
not_set_str, &dealloc, colorize); not_set_str, &dealloc);
if (terse) { if (terse) {
if (escape) { if (escape) {
@@ -1327,7 +1336,7 @@ print_data (NmCli *nmc)
char *value; char *value;
row = g_ptr_array_index (nmc->output_data, j); row = g_ptr_array_index (nmc->output_data, j);
field_names = row[0].flags & NMC_OF_FLAG_FIELD_NAMES; field_names = row[0].flags & NMC_OF_FLAG_FIELD_NAMES;
value = get_value_to_print (row+i, field_names, "--", &dealloc, FALSE); value = get_value_to_print (NULL, row+i, field_names, "--", &dealloc);
len = nmc_string_screen_width (value, NULL); len = nmc_string_screen_width (value, NULL);
max_width = len > max_width ? len : max_width; max_width = len > max_width ? len : max_width;
if (dealloc) if (dealloc)

View File

@@ -76,7 +76,7 @@ void nmc_terminal_show_progress (const char *str);
const char *nmc_term_color_sequence (NmcTermColor color); const char *nmc_term_color_sequence (NmcTermColor color);
const char *nmc_term_format_sequence (NmcTermFormat format); const char *nmc_term_format_sequence (NmcTermFormat format);
NmcTermColor nmc_term_color_parse_string (const char *str, GError **error); NmcTermColor nmc_term_color_parse_string (const char *str, GError **error);
char *nmc_colorize (NmcTermColor color, NmcTermFormat format, const char * fmt, ...); char *nmc_colorize (NmCli *nmc, NmcTermColor color, NmcTermFormat format, const char * fmt, ...);
void nmc_filter_out_colors_inplace (char *str); void nmc_filter_out_colors_inplace (char *str);
char *nmc_filter_out_colors (const char *str); char *nmc_filter_out_colors (const char *str);
char *nmc_get_user_input (const char *ask_str); char *nmc_get_user_input (const char *ask_str);

View File

@@ -1562,14 +1562,16 @@ nm_device_get_product (NMDevice *device)
g_return_val_if_fail (NM_IS_DEVICE (device), NULL); g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
priv = NM_DEVICE_GET_PRIVATE (device); priv = NM_DEVICE_GET_PRIVATE (device);
if (!priv->product) { if (!priv->product)
priv->product = _get_udev_property (device, "ID_MODEL_ENC", "ID_MODEL_FROM_DATABASE"); priv->product = _get_udev_property (device, "ID_MODEL_ENC", "ID_MODEL_FROM_DATABASE");
if (!priv->product) {
/* Sometimes ID_PRODUCT_FROM_DATABASE is used? */ /* Sometimes ID_PRODUCT_FROM_DATABASE is used? */
if (!priv->product)
priv->product = _get_udev_property (device, "ID_MODEL_ENC", "ID_PRODUCT_FROM_DATABASE"); priv->product = _get_udev_property (device, "ID_MODEL_ENC", "ID_PRODUCT_FROM_DATABASE");
}
_nm_object_queue_notify (NM_OBJECT (device), NM_DEVICE_PRODUCT); if (!priv->product)
} priv->product = g_strdup ("");
return priv->product; return priv->product;
} }
@@ -1590,10 +1592,13 @@ nm_device_get_vendor (NMDevice *device)
g_return_val_if_fail (NM_IS_DEVICE (device), NULL); g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
priv = NM_DEVICE_GET_PRIVATE (device); priv = NM_DEVICE_GET_PRIVATE (device);
if (!priv->vendor) {
if (!priv->vendor)
priv->vendor = _get_udev_property (device, "ID_VENDOR_ENC", "ID_VENDOR_FROM_DATABASE"); priv->vendor = _get_udev_property (device, "ID_VENDOR_ENC", "ID_VENDOR_FROM_DATABASE");
_nm_object_queue_notify (NM_OBJECT (device), NM_DEVICE_VENDOR);
} if (!priv->vendor)
priv->vendor = g_strdup ("");
return priv->vendor; return priv->vendor;
} }

View File

@@ -1010,7 +1010,9 @@ properties_changed (GDBusProxy *proxy,
G_STMT_START { \ G_STMT_START { \
if (g_variant_is_of_type (value, vtype)) { \ if (g_variant_is_of_type (value, vtype)) { \
ctype *param = (ctype *) field; \ ctype *param = (ctype *) field; \
*param = getter (value); \ ctype newval = getter (value); \
different = *param != newval; \
*param = newval; \
} else { \ } else { \
success = FALSE; \ success = FALSE; \
goto done; \ goto done; \
@@ -1024,20 +1026,29 @@ demarshal_generic (NMObject *object,
gpointer field) gpointer field)
{ {
gboolean success = TRUE; gboolean success = TRUE;
gboolean different = FALSE;
if (pspec->value_type == G_TYPE_STRING) { if (pspec->value_type == G_TYPE_STRING) {
if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) { if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)) {
char **param = (char **) field; char **param = (char **) field;
const char *newval = g_variant_get_string (value, NULL);
different = !!g_strcmp0 (*param, newval);
if (different) {
g_free (*param); g_free (*param);
*param = g_variant_dup_string (value, NULL); *param = g_strdup (newval);
}
} else if (g_variant_is_of_type (value, G_VARIANT_TYPE_OBJECT_PATH)) { } else if (g_variant_is_of_type (value, G_VARIANT_TYPE_OBJECT_PATH)) {
char **param = (char **) field; char **param = (char **) field;
g_free (*param); const char *newval = g_variant_get_string (value, NULL);
*param = g_variant_dup_string (value, NULL);
/* Handle "NULL" object paths */ /* Handle "NULL" object paths */
if (g_strcmp0 (*param, "/") == 0) { if (g_strcmp0 (newval, "/") == 0)
newval = NULL;
different = !!g_strcmp0 (*param, newval);
if (different) {
g_free (*param); g_free (*param);
*param = NULL; *param = g_strdup (newval);
} }
} else { } else {
success = FALSE; success = FALSE;
@@ -1045,50 +1056,78 @@ demarshal_generic (NMObject *object,
} }
} else if (pspec->value_type == G_TYPE_STRV) { } else if (pspec->value_type == G_TYPE_STRV) {
char ***param = (char ***)field; char ***param = (char ***)field;
if (*param) const char **newval;
gsize i;
newval = g_variant_get_strv (value, NULL);
if (!*param)
different = TRUE;
else {
if (!_nm_utils_strv_equal ((char **) newval, *param)) {
different = TRUE;
g_strfreev (*param); g_strfreev (*param);
*param = g_variant_dup_strv (value, NULL); }
}
if (different) {
for (i = 0; newval[i]; i++)
newval[i] = g_strdup (newval[i]);
*param = (char **) newval;
} else
g_free (newval);
} else if (pspec->value_type == G_TYPE_BYTES) { } else if (pspec->value_type == G_TYPE_BYTES) {
GBytes **param = (GBytes **)field; GBytes **param = (GBytes **)field;
gconstpointer val; gconstpointer val, old_val = NULL;
gsize length; gsize length, old_length = 0;
val = g_variant_get_fixed_array (value, &length, 1);
if (*param)
old_val = g_bytes_get_data (*param, &old_length);
different = old_length != length
|| ( length > 0
&& memcmp (old_val, val, length) != 0);
if (different) {
if (*param) if (*param)
g_bytes_unref (*param); g_bytes_unref (*param);
val = g_variant_get_fixed_array (value, &length, 1); *param = length > 0 ? g_bytes_new (val, length) : NULL;
if (length) }
*param = g_bytes_new (val, length);
else
*param = NULL;
} else if (G_IS_PARAM_SPEC_ENUM (pspec)) { } else if (G_IS_PARAM_SPEC_ENUM (pspec)) {
int *param = (int *) field; int *param = (int *) field;
int newval = 0;
if (g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)) if (g_variant_is_of_type (value, G_VARIANT_TYPE_INT32))
*param = g_variant_get_int32 (value); newval = g_variant_get_int32 (value);
else if (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)) else if (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32))
*param = g_variant_get_uint32 (value); newval = g_variant_get_uint32 (value);
else { else {
success = FALSE; success = FALSE;
goto done; goto done;
} }
different = *param != newval;
*param = newval;
} else if (G_IS_PARAM_SPEC_FLAGS (pspec)) { } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
guint *param = (guint *) field; guint *param = (guint *) field;
guint newval = 0;
if (g_variant_is_of_type (value, G_VARIANT_TYPE_INT32)) if (g_variant_is_of_type (value, G_VARIANT_TYPE_INT32))
*param = g_variant_get_int32 (value); newval = g_variant_get_int32 (value);
else if (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32)) else if (g_variant_is_of_type (value, G_VARIANT_TYPE_UINT32))
*param = g_variant_get_uint32 (value); newval = g_variant_get_uint32 (value);
else { else {
success = FALSE; success = FALSE;
goto done; goto done;
} }
different = *param != newval;
*param = newval;
} else if (pspec->value_type == G_TYPE_BOOLEAN) } else if (pspec->value_type == G_TYPE_BOOLEAN)
HANDLE_TYPE (G_VARIANT_TYPE_BOOLEAN, gboolean, g_variant_get_boolean); HANDLE_TYPE (G_VARIANT_TYPE_BOOLEAN, gboolean, g_variant_get_boolean);
else if (pspec->value_type == G_TYPE_UCHAR) else if (pspec->value_type == G_TYPE_UCHAR)
HANDLE_TYPE (G_VARIANT_TYPE_BYTE, guchar, g_variant_get_byte); HANDLE_TYPE (G_VARIANT_TYPE_BYTE, guchar, g_variant_get_byte);
else if (pspec->value_type == G_TYPE_DOUBLE) else if (pspec->value_type == G_TYPE_DOUBLE) {
NM_PRAGMA_WARNING_DISABLE("-Wfloat-equal")
HANDLE_TYPE (G_VARIANT_TYPE_DOUBLE, gdouble, g_variant_get_double); HANDLE_TYPE (G_VARIANT_TYPE_DOUBLE, gdouble, g_variant_get_double);
else if (pspec->value_type == G_TYPE_INT) NM_PRAGMA_WARNING_REENABLE
} else if (pspec->value_type == G_TYPE_INT)
HANDLE_TYPE (G_VARIANT_TYPE_INT32, gint, g_variant_get_int32); HANDLE_TYPE (G_VARIANT_TYPE_INT32, gint, g_variant_get_int32);
else if (pspec->value_type == G_TYPE_UINT) else if (pspec->value_type == G_TYPE_UINT)
HANDLE_TYPE (G_VARIANT_TYPE_UINT32, guint, g_variant_get_uint32); HANDLE_TYPE (G_VARIANT_TYPE_UINT32, guint, g_variant_get_uint32);
@@ -1111,6 +1150,7 @@ demarshal_generic (NMObject *object,
done: done:
if (success) { if (success) {
if (different)
_nm_object_queue_notify (object, pspec->name); _nm_object_queue_notify (object, pspec->name);
} else { } else {
dbgmsg ("%s: %s:%s (type %s) couldn't be set from D-Bus type %s.", dbgmsg ("%s: %s:%s (type %s) couldn't be set from D-Bus type %s.",

View File

@@ -33,7 +33,7 @@ nmcli \- command\(hyline tool for controlling NetworkManager
.sp .sp
.IR OBJECT " := { " .IR OBJECT " := { "
.BR general " | " networking " | " radio " | " connection " | " device " | " agent .BR general " | " networking " | " radio " | " connection " | " device " | " agent " | " monitor
.RI " }" .RI " }"
.sp .sp
@@ -259,6 +259,16 @@ are supplied, mobile broadband status is printed; \fIon\fP enables mobile broadb
Show or set all previously mentioned radio switches at the same time. Show or set all previously mentioned radio switches at the same time.
.RE .RE
.TP
.B monitor \- monitor NetworkManager
.br
Use this object to observe NetworkManager activity. Watches for changes
in connectivity state, devices or connection profiles.
.br
See also \fImonitor\fP command of \fIconnection\fP or \fIdevice\fP object
to watch for changes in certain objects or object classes.
.RE
.TP .TP
.B connection \- start, stop, and manage network connections .B connection \- start, stop, and manage network connections
.sp .sp
@@ -278,7 +288,7 @@ be saved as two connections which both apply to eth0, one for DHCP (called
connected to the DHCP-enabled network the user would run "nmcli con up default" connected to the DHCP-enabled network the user would run "nmcli con up default"
, and when connected to the static network the user would run "nmcli con up testing". , and when connected to the static network the user would run "nmcli con up testing".
.TP .TP
.SS \fICOMMAND\fP := { show | up | down | add | edit | modify | delete | reload | load } .SS \fICOMMAND\fP := { show | up | down | add | edit | modify | delete | monitor | reload | load }
.sp .sp
.RS .RS
.TP .TP
@@ -779,6 +789,19 @@ See \fBconnection show\fP above for the description of the <ID>-specifying keywo
.br .br
If '--wait' option is not specified, the default timeout will be 10 seconds. If '--wait' option is not specified, the default timeout will be 10 seconds.
.TP .TP
.B monitor [ id | uuid | path ] <ID> ...
.br
Monitor connection profile activity. This command prints a line whenever the
specified connection changes. The connection to be monitored is identified by
its name, UUID or D-Bus path. If <ID> is ambiguous, a keyword \fIid\fP,
\fIuuid\fP or \fIpath\fP can be used.
.br
See \fBconnection show\fP above for the description of the <ID>-specifying keywords.
.br
Monitors all connection profiles in case none is specified. The command terminates
when all monitored connections disappear. If you want to monitor connection creation
consider using the global monitor with \fInmcli monitor\fP command.
.TP
.B reload .B reload
.br .br
Reload all connection files from disk. \fINetworkManager\fP does not monitor Reload all connection files from disk. \fINetworkManager\fP does not monitor
@@ -799,7 +822,7 @@ of its latest state.
.B device - show and manage network interfaces .B device - show and manage network interfaces
.br .br
.TP .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 .sp
.RS .RS
.TP .TP
@@ -843,6 +866,15 @@ Hardware devices (like Ethernet) cannot be deleted by the command.
.br .br
If '--wait' option is not specified, the default timeout will be 10 seconds. If '--wait' option is not specified, the default timeout will be 10 seconds.
.TP .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. If you want to monitor device addition consider
using the global monitor with \fInmcli monitor\fP command.
.TP
.B wifi [list [ifname <ifname>] [bssid <BSSID>]] .B wifi [list [ifname <ifname>] [bssid <BSSID>]]
.br .br
List available Wi\(hyFi access points. The \fIifname\fP and \fIbssid\fP options List available Wi\(hyFi access points. The \fIifname\fP and \fIbssid\fP options