summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-04-04 15:10:05 +0200
committerThomas Haller <thaller@redhat.com>2020-04-04 19:49:09 +0200
commit4987a7cd6bf63c70c5d96ea90cbcfb6f7f148379 (patch)
tree9e3a7468da274a60fd12985745d6c30690a5f841
parent306414b93d447e915b6de94b9b7410ff7aadc4cf (diff)
downloadNetworkManager-th/cli-globals-2.tar.gz
-rw-r--r--Makefile.am6
-rw-r--r--clients/cli/agent.c153
-rw-r--r--clients/cli/agent.h13
-rw-r--r--clients/cli/common.c209
-rw-r--r--clients/cli/common.h25
-rw-r--r--clients/cli/connections.c821
-rw-r--r--clients/cli/connections.h2
-rw-r--r--clients/cli/general.c777
-rw-r--r--clients/cli/general.h17
-rw-r--r--clients/cli/nmcli.c502
-rw-r--r--clients/cli/nmcli.h195
-rw-r--r--clients/cli/utils.c27
-rw-r--r--clients/cli/utils.h30
13 files changed, 1596 insertions, 1181 deletions
diff --git a/Makefile.am b/Makefile.am
index e1b7b12abd..8fce37b982 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4479,17 +4479,15 @@ clients_cli_nmcli_SOURCES = \
clients/cli/utils.c \
clients/cli/utils.h \
clients/cli/agent.c \
- clients/cli/agent.h \
clients/cli/general.c \
- clients/cli/general.h \
+ clients/cli/nmcli.c \
+ clients/cli/nmcli.h \
clients/cli/connections.c \
clients/cli/connections.h \
clients/cli/devices.c \
clients/cli/devices.h \
clients/cli/settings.c \
clients/cli/settings.h \
- clients/cli/nmcli.c \
- clients/cli/nmcli.h \
clients/cli/polkit-agent.c \
clients/cli/polkit-agent.h \
$(NULL)
diff --git a/clients/cli/agent.c b/clients/cli/agent.c
index 93b5ca079a..d82c251454 100644
--- a/clients/cli/agent.c
+++ b/clients/cli/agent.c
@@ -5,8 +5,6 @@
#include "nm-default.h"
-#include "agent.h"
-
#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
@@ -70,6 +68,7 @@ set_deftext (void)
static gboolean
get_secrets_from_user (const NmcConfig *nmc_config,
+ NmcReadlineStatus *readline_status,
const char *request_id,
const char *title,
const char *msg,
@@ -90,9 +89,9 @@ get_secrets_from_user (const NmcConfig *nmc_config,
pre_input_deftext = g_strdup (secret->value);
}
if (secret->no_prompt_entry_id)
- pwd = nmc_readline (nmc_config, "%s: ", secret->pretty_name);
+ pwd = nmc_readline (nmc_config, readline_status, "%s: ", secret->pretty_name);
else
- pwd = nmc_readline (nmc_config, "%s (%s): ", secret->pretty_name, secret->entry_id);
+ pwd = nmc_readline (nmc_config, readline_status, "%s (%s): ", secret->pretty_name, secret->entry_id);
/* No password provided, cancel the secrets. */
if (!pwd)
@@ -117,39 +116,12 @@ secrets_requested (NMSecretAgentSimple *agent,
if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
nmc_terminal_erase_line ();
- success = get_secrets_from_user (&nmc->nmc_config, request_id, title, msg, secrets);
+ success = get_secrets_from_user (&nmc->nmc_config, &nmc->readline_status, request_id, title, msg, secrets);
nm_secret_agent_simple_response (agent,
request_id,
success ? secrets : NULL);
}
-static NMCResultCode
-do_agent_secret (NmCli *nmc, int argc, char **argv)
-{
- next_arg (nmc, &argc, &argv, NULL);
- if (nmc->complete)
- return nmc->return_value;
-
- /* Create secret agent */
- nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent");
- if (nmc->secret_agent) {
- /* We keep running */
- nmc->should_wait++;
-
- nm_secret_agent_simple_enable (nmc->secret_agent, NULL);
- g_signal_connect (nmc->secret_agent,
- NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS,
- G_CALLBACK (secrets_requested),
- nmc);
- g_print (_("nmcli successfully registered as a NetworkManager's secret agent.\n"));
- } else {
- g_string_printf (nmc->return_text, _("Error: secret agent initialization failed"));
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- }
-
- return nmc->return_value;
-}
-
static void
polkit_registered (gpointer instance,
gpointer user_data)
@@ -162,83 +134,80 @@ polkit_error (gpointer instance,
const char *error,
gpointer user_data)
{
- g_main_loop_quit (loop);
+ NmCli *nmc = user_data;
+
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_UNKNOWN,
+ _("Error: polkit agent failed: %s"),
+ error);
}
-static NMCResultCode
-do_agent_polkit (NmCli *nmc, int argc, char **argv)
+static void
+do_agent (const NMCCommand *cmd,
+ NmCli *nmc,
+ int argc,
+ const char *const*argv)
{
gs_free_error GError *error = NULL;
+ gboolean with_polkit_agent = NM_IN_STRSET (cmd->cmd, NULL, "all", "polkit");
+ gboolean with_secret_agent = NM_IN_STRSET (cmd->cmd, NULL, "all", "secret");
+
+ nm_assert (with_polkit_agent || with_secret_agent);
+
+ if (with_polkit_agent) {
+ if (!nmc_polkit_agent_init (nmc, TRUE, &error)) {
+ g_dbus_error_strip_remote_error (error);
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_UNKNOWN,
+ _("Error: polkit agent initialization failed: %s"),
+ error->message);
+ return;
+ }
+ }
- next_arg (nmc, &argc, &argv, NULL);
- if (nmc->complete)
- return nmc->return_value;
-
- if (!nmc_polkit_agent_init (nmc, TRUE, &error)) {
- g_dbus_error_strip_remote_error (error);
- g_string_printf (nmc->return_text,
- _("Error: polkit agent initialization failed: %s"),
- error->message);
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- } else {
- /* We keep running */
- nmc->should_wait++;
+ if (with_secret_agent) {
+ nmc->secret_agent = nm_secret_agent_simple_new ("nmcli-agent");
+ if (!nmc->secret_agent) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_UNKNOWN,
+ _("Error: secret agent initialization failed"));
+ return;
+ }
+ }
+
+ nmc_run_status_wait_push (&nmc->run_status);
+
+ if (with_polkit_agent) {
g_signal_connect (nmc->pk_listener,
NM_POLKIT_LISTENER_SIGNAL_ERROR,
G_CALLBACK (polkit_error),
- NULL);
+ nmc);
g_signal_connect (nmc->pk_listener,
NM_POLKIT_LISTENER_SIGNAL_REGISTERED,
G_CALLBACK (polkit_registered),
- NULL);
-
- /* keep running */
- nmc->should_wait++;
- }
-
- return nmc->return_value;
-}
-
-static NMCResultCode
-do_agent_all (NmCli *nmc, int argc, char **argv)
-{
- NMCResultCode secret_res;
-
- next_arg (nmc, &argc, &argv, NULL);
- if (nmc->complete)
- return nmc->return_value;
-
- /* Run both secret and polkit agent */
- secret_res = do_agent_secret (nmc, argc, argv);
- if (secret_res != NMC_RESULT_SUCCESS) {
- g_printerr ("%s\n", nmc->return_text->str);
- g_string_truncate (nmc->return_text, 0);
+ nmc);
}
- nmc->return_value = do_agent_polkit (nmc, argc, argv);
- if (nmc->return_value != NMC_RESULT_SUCCESS) {
- g_printerr ("%s\n", nmc->return_text->str);
- g_string_truncate (nmc->return_text, 0);
+ if (with_secret_agent) {
+ nm_secret_agent_simple_enable (nmc->secret_agent, NULL);
+ g_signal_connect (nmc->secret_agent,
+ NM_SECRET_AGENT_SIMPLE_REQUEST_SECRETS,
+ G_CALLBACK (secrets_requested),
+ nmc);
+ g_print (_("nmcli successfully registered as a NetworkManager's secret agent.\n"));
}
-
- if (nmc->return_value == NMC_RESULT_SUCCESS && secret_res != NMC_RESULT_SUCCESS)
- nmc->return_value = secret_res;
-
- return nmc->return_value;
}
-static const NMCCommand agent_cmds[] = {
- { "secret", do_agent_secret, usage_agent_secret, TRUE, TRUE },
- { "polkit", do_agent_polkit, usage_agent_polkit, TRUE, TRUE },
- { "all", do_agent_all, usage_agent_all, TRUE, TRUE },
- { NULL, do_agent_all, usage, TRUE, TRUE },
-};
-
-NMCResultCode
-do_agent (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_do_agent (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
+ static const NMCCommand agent_cmds[] = {
+ { "secret", do_agent, usage_agent_secret, TRUE, TRUE },
+ { "polkit", do_agent, usage_agent_polkit, TRUE, TRUE },
+ { "all", do_agent, usage_agent_all, TRUE, TRUE },
+ { NULL, do_agent, usage, TRUE, TRUE },
+ };
+
next_arg (nmc, &argc, &argv, NULL);
nmc_do_cmd (nmc, agent_cmds, *argv, argc, argv);
-
- return nmc->return_value;
}
diff --git a/clients/cli/agent.h b/clients/cli/agent.h
deleted file mode 100644
index aad56bba1c..0000000000
--- a/clients/cli/agent.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2014 Red Hat, Inc.
- */
-
-#ifndef __NMC_AGENT_H__
-#define __NMC_AGENT_H__
-
-#include "nmcli.h"
-
-NMCResultCode do_agent (NmCli *nmc, int argc, char **argv);
-
-#endif /* __NMC_AGENT_H__ */
diff --git a/clients/cli/common.c b/clients/cli/common.c
index 7e9bcba860..14285b71bf 100644
--- a/clients/cli/common.c
+++ b/clients/cli/common.c
@@ -672,6 +672,7 @@ vpn_openconnect_get_secrets (NMConnection *connection, GPtrArray *secrets)
static gboolean
get_secrets_from_user (const NmcConfig *nmc_config,
+ NmcReadlineStatus *readline_status,
const char *request_id,
const char *title,
const char *msg,
@@ -716,9 +717,9 @@ get_secrets_from_user (const NmcConfig *nmc_config,
: TRUE;
if (secret->no_prompt_entry_id)
- pwd = nmc_readline_echo (nmc_config, echo_on, "%s: ", secret->pretty_name);
+ pwd = nmc_readline_echo (nmc_config, readline_status, echo_on, "%s: ", secret->pretty_name);
else
- pwd = nmc_readline_echo (nmc_config, echo_on, "%s (%s): ", secret->pretty_name, secret->entry_id);
+ pwd = nmc_readline_echo (nmc_config, readline_status, echo_on, "%s (%s): ", secret->pretty_name, secret->entry_id);
if (!pwd)
pwd = g_strdup ("");
@@ -782,6 +783,7 @@ nmc_secrets_requested (NMSecretAgentSimple *agent,
}
success = get_secrets_from_user (&nmc->nmc_config,
+ &nmc->readline_status,
request_id,
title,
msg,
@@ -826,7 +828,6 @@ nmc_unique_connection_name (const GPtrArray *connections, const char *try_name)
}
/* readline state variables */
-static gboolean nmcli_in_readline = FALSE;
static gboolean rl_got_line;
static char *rl_string;
@@ -844,15 +845,15 @@ nmc_cleanup_readline (void)
}
gboolean
-nmc_get_in_readline (void)
+nmc_get_in_readline (NmcReadlineStatus *readline_status)
{
- return nmcli_in_readline;
+ return readline_status->in_readline;
}
void
-nmc_set_in_readline (gboolean in_readline)
+nmc_set_in_readline (NmcReadlineStatus *readline_status, gboolean in_readline)
{
- nmcli_in_readline = in_readline;
+ readline_status->in_readline = in_readline;
}
static void
@@ -874,11 +875,12 @@ stdin_ready_cb (int fd,
static char *
nmc_readline_helper (const NmcConfig *nmc_config,
+ NmcReadlineStatus *readline_status,
const char *prompt)
{
GSource *io_source;
- nmc_set_in_readline (TRUE);
+ nmc_set_in_readline (readline_status, TRUE);
io_source = nm_g_unix_fd_source_new (STDIN_FILENO,
G_IO_IN,
@@ -895,11 +897,11 @@ read_again:
while ( !rl_got_line
&& g_main_loop_is_running (loop)
- && !nmc_seen_sigint ())
+ && !nmc_seen_sigint (readline_status))
g_main_context_iteration (NULL, TRUE);
/* If Ctrl-C was detected, complete the line */
- if (nmc_seen_sigint ()) {
+ if (nmc_seen_sigint (readline_status)) {
rl_echo_signal_char (SIGINT);
if (!rl_got_line) {
rl_stuff_char ('\n');
@@ -911,9 +913,9 @@ read_again:
if (rl_string && *rl_string)
add_history (rl_string);
- if (nmc_seen_sigint ()) {
+ if (nmc_seen_sigint (readline_status)) {
/* Ctrl-C */
- nmc_clear_sigint ();
+ nmc_clear_sigint (readline_status);
if ( nmc_config->in_editor
|| (rl_string && *rl_string)) {
/* In editor, or the line is not empty */
@@ -937,7 +939,7 @@ read_again:
nm_clear_g_source_inst (&io_source);
- nmc_set_in_readline (FALSE);
+ nmc_set_in_readline (readline_status, FALSE);
return rl_string;
}
@@ -958,18 +960,19 @@ read_again:
*/
char *
nmc_readline (const NmcConfig *nmc_config,
+ NmcReadlineStatus *readline_status,
const char *prompt_fmt,
...)
{
- va_list args;
gs_free char *prompt = NULL;
+ va_list args;
rl_initialize ();
va_start (args, prompt_fmt);
prompt = g_strdup_vprintf (prompt_fmt, args);
va_end (args);
- return nmc_readline_helper (nmc_config, prompt);
+ return nmc_readline_helper (nmc_config, readline_status, prompt);
}
static void
@@ -1005,6 +1008,7 @@ nmc_secret_redisplay (void)
*/
char *
nmc_readline_echo (const NmcConfig *nmc_config,
+ NmcReadlineStatus *readline_status,
gboolean echo_on,
const char *prompt_fmt,
...)
@@ -1032,7 +1036,7 @@ nmc_readline_echo (const NmcConfig *nmc_config,
rl_redisplay_function = nmc_secret_redisplay;
}
- str = nmc_readline_helper (nmc_config, prompt);
+ str = nmc_readline_helper (nmc_config, readline_status, prompt);
/* Restore the non-hiding behavior */
if (!echo_on) {
@@ -1196,101 +1200,40 @@ nmc_parse_lldp_capabilities (guint value)
}
static void
-command_done (GObject *object, GAsyncResult *res, gpointer user_data)
+nmc_complete_help (const char *prefix)
{
- GTask *task = G_TASK (res);
- NmCli *nmc = user_data;
- gs_free_error GError *error = NULL;
-
- if (!g_task_propagate_boolean (task, &error)) {
- nmc->return_value = error->code;
- g_string_assign (nmc->return_text, error->message);
- }
-
- if (!nmc->should_wait)
- g_main_loop_quit (loop);
+ nmc_complete_strings (prefix, "help");
+ if (*prefix == '-')
+ nmc_complete_strings (prefix, "-help", "--help");
}
-typedef struct {
- const NMCCommand *cmd;
- int argc;
- char **argv;
- GTask *task;
-} CmdCall;
-
-static void
-call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv);
-
static void
got_client (GObject *source_object, GAsyncResult *res, gpointer user_data)
{
- gs_unref_object GTask *task = NULL;
+ gs_unref_object NMClient *client = NM_CLIENT (source_object);
gs_free_error GError *error = NULL;
- CmdCall *call = user_data;
- NmCli *nmc;
-
- nm_assert (NM_IS_CLIENT (source_object));
+ nm_auto_pop_run_status NmCli *nmc = NULL;
+ const NMCCommand *c;
+ gpointer argc_p;
+ int argc;
+ const char *const*argv;
- task = g_steal_pointer (&call->task);
- nmc = g_task_get_task_data (task);
+ nm_utils_user_data_unpack (user_data, &nmc, &c, &argc_p, &argv);
- nmc->should_wait--;
+ argc = GPOINTER_TO_INT (argc_p);
if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source_object),
res,
&error)) {
- g_object_unref (source_object);
- g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_UNKNOWN,
- _("Error: Could not create NMClient object: %s."),
- error->message);
- } else {
- nmc->client = NM_CLIENT (source_object);
- call_cmd (nmc, g_steal_pointer (&task), call->cmd, call->argc, call->argv);
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: Could not create NMClient object: %s."),
+ error->message);
}
- g_slice_free (CmdCall, call);
-}
-
-static void
-call_cmd (NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, char **argv)
-{
- CmdCall *call;
-
- if (nmc->client || !cmd->needs_client) {
-
- /* Check whether NetworkManager is running */
- if (cmd->needs_nm_running && !nm_client_get_nm_running (nmc->client)) {
- g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_NM_NOT_RUNNING,
- _("Error: NetworkManager is not running."));
- } else {
- nmc->return_value = cmd->func (nmc, argc, argv);
- g_task_return_boolean (task, TRUE);
- }
-
- g_object_unref (task);
- } else {
- nm_assert (nmc->client == NULL);
-
- nmc->should_wait++;
- call = g_slice_new0 (CmdCall);
- call->cmd = cmd;
- call->argc = argc;
- call->argv = argv;
- call->task = task;
- nmc_client_new_async (NULL,
- got_client,
- call,
- NM_CLIENT_INSTANCE_FLAGS, (guint) NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS,
- NULL);
- }
-}
+ nmc->client = g_steal_pointer (&client);
-static void
-nmc_complete_help (const char *prefix)
-{
- nmc_complete_strings (prefix, "help");
- if (*prefix == '-')
- nmc_complete_strings (prefix, "-help", "--help");
+ c->func (c, nmc, argc, argv);
}
/**
@@ -1313,26 +1256,30 @@ nmc_complete_help (const char *prefix)
* no callback to free the memory in (for simplicity).
*/
void
-nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char **argv)
+nmc_do_cmd (NmCli *nmc,
+ const NMCCommand *cmds,
+ const char *cmd,
+ int argc,
+ const char *const*argv)
{
const NMCCommand *c;
- gs_unref_object GTask *task = NULL;
- task = nm_g_task_new (NULL, NULL, nmc_do_cmd, command_done, nmc);
- g_task_set_task_data (task, nmc, NULL);
+ nmc_run_status_wait_push (&nmc->run_status);
- if (argc == 0 && nmc->complete) {
- g_task_return_boolean (task, TRUE);
+ if ( argc == 0
+ && nmc->complete) {
+ nmc_run_status_return_success (&nmc->run_status);
return;
}
- if (argc == 1 && nmc->complete) {
+ if ( argc == 1
+ && nmc->complete) {
for (c = cmds; c->cmd; ++c) {
if (!*cmd || matches (cmd, c->cmd))
g_print ("%s\n", c->cmd);
}
nmc_complete_help (cmd);
- g_task_return_boolean (task, TRUE);
+ nmc_run_status_return_success (&nmc->run_status);
return;
}
@@ -1343,31 +1290,61 @@ nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char
if (c->cmd) {
/* A valid command was specified. */
- if (c->usage && argc == 2 && nmc->complete)
- nmc_complete_help (*(argv+1));
- if (!nmc->complete && c->usage && nmc_arg_is_help (*(argv+1))) {
+ if ( c->usage
+ && argc == 2
+ && nmc->complete)
+ nmc_complete_help (argv[1]);
+ if ( !nmc->complete
+ && c->usage
+ && nmc_arg_is_help (argv[1])) {
c->usage ();
- g_task_return_boolean (task, TRUE);
- } else {
- call_cmd (nmc, g_steal_pointer (&task), c, argc, argv);
+ nmc_run_status_return_success (&nmc->run_status);
+ return;
}
} else if (cmd) {
/* Not a known command. */
if (nmc_arg_is_help (cmd) && c->usage) {
c->usage ();
- g_task_return_boolean (task, TRUE);
- } else {
- g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("Error: argument '%s' not understood. Try passing --help instead."), cmd);
+ nmc_run_status_return_success (&nmc->run_status);
+ return;
}
+
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: argument '%s' not understood. Try passing --help instead."),
+ cmd);
+ return;
} else if (c->func) {
/* No command, run the default handler. */
- call_cmd (nmc, g_steal_pointer (&task), c, argc, argv);
} else {
/* No command and no default handler. */
- g_task_return_new_error (task, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
- _("Error: missing argument. Try passing --help."));
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: missing argument. Try passing --help."));
+ return;
+ }
+
+ if ( nmc->client
+ || !c->needs_client) {
+
+ if ( c->needs_nm_running
+ && !nm_client_get_nm_running (nmc->client)) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_NM_NOT_RUNNING,
+ _("Error: NetworkManager is not running."));
+ return;
+ }
+
+ c->func (c, nmc, argc, argv);
+ return;
}
+
+ nmc_run_status_wait_push (&nmc->run_status);
+ nmc_client_new_async (nmc->run_status.cancellable,
+ got_client,
+ nm_utils_user_data_pack (nmc, cmd, GINT_TO_POINTER (argc), argv),
+ NM_CLIENT_INSTANCE_FLAGS, (guint) NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS,
+ NULL);
}
/**
diff --git a/clients/cli/common.h b/clients/cli/common.h
index f8fad8c673..26e245da66 100644
--- a/clients/cli/common.h
+++ b/clients/cli/common.h
@@ -44,17 +44,20 @@ char *nmc_unique_connection_name (const GPtrArray *connections,
void nmc_cleanup_readline (void);
char *nmc_readline (const NmcConfig *nmc_config,
+ NmcReadlineStatus *readline_status,
const char *prompt_fmt,
- ...) G_GNUC_PRINTF (2, 3);
+ ...) G_GNUC_PRINTF (3, 4);
char *nmc_readline_echo (const NmcConfig *nmc_config,
+ NmcReadlineStatus *readline_status,
gboolean echo_on,
const char *prompt_fmt,
- ...) G_GNUC_PRINTF (3, 4);
+ ...) G_GNUC_PRINTF (4, 5);
NmcCompEntryFunc nmc_rl_compentry_func_wrap (const char *const*values);
char *nmc_rl_gen_func_basic (const char *text, int state, const char *const*words);
char *nmc_rl_gen_func_ifnames (const char *text, int state);
-gboolean nmc_get_in_readline (void);
-void nmc_set_in_readline (gboolean in_readline);
+
+gboolean nmc_get_in_readline (NmcReadlineStatus *readline_status);
+void nmc_set_in_readline (NmcReadlineStatus *readline_status, gboolean in_readline);
/* for pre-filling a string to readline prompt */
extern char *nmc_rl_pre_input_deftext;
@@ -62,15 +65,11 @@ int nmc_rl_set_deftext (void);
char *nmc_parse_lldp_capabilities (guint value);
-typedef struct {
- const char *cmd;
- NMCResultCode (*func) (NmCli *nmc, int argc, char **argv);
- void (*usage) (void);
- gboolean needs_client;
- gboolean needs_nm_running;
-} NMCCommand;
-
-void nmc_do_cmd (NmCli *nmc, const NMCCommand cmds[], const char *cmd, int argc, char **argv);
+void nmc_do_cmd (NmCli *nmc,
+ const NMCCommand *cmds,
+ const char *cmd,
+ int argc,
+ const char *const*argv);
void nmc_complete_strv (const char *prefix, gssize nargs, const char *const*args);
diff --git a/clients/cli/connections.c b/clients/cli/connections.c
index 7fe22adf63..75795560cb 100644
--- a/clients/cli/connections.c
+++ b/clients/cli/connections.c
@@ -885,8 +885,6 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_groups[] = {
#define CON_SHOW_DETAIL_GROUP_PROFILE "profile"
#define CON_SHOW_DETAIL_GROUP_ACTIVE "active"
-static guint progress_id = 0; /* ID of event source for displaying progress */
-
/* for readline TAB completion in editor */
typedef struct {
NmCli *nmc;
@@ -1223,14 +1221,6 @@ usage_connection_export (void)
"The data are directed to standard output or to a file if a name is given.\n\n"));
}
-static void
-quit (void)
-{
- if (nm_clear_g_source (&progress_id))
- nmc_terminal_erase_line ();
- g_main_loop_quit (loop);
-}
-
static char *
construct_header_name (const char *base, const char *spec)
{
@@ -1346,9 +1336,9 @@ update_secrets_in_connection (NMRemoteConnection *remote, NMConnection *local)
static gboolean
nmc_connection_profile_details (NMConnection *connection, NmCli *nmc)
{
- GError *error = NULL;
- GArray *print_settings_array;
- GPtrArray *prop_array = NULL;
+ gs_free_error GError *error = NULL;
+ gs_unref_array GArray *print_settings_array = NULL;
+ gs_unref_ptrarray GPtrArray *prop_array = NULL;
guint i;
char *fields_str;
char *fields_all = NMC_FIELDS_SETTINGS_NAMES_ALL;
@@ -1366,12 +1356,14 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc)
print_settings_array = parse_output_fields (fields_str, (const NMMetaAbstractInfo *const*) nm_meta_setting_infos_editor_p (),
TRUE, &prop_array, &error);
if (error) {
- g_string_printf (nmc->return_text, _("Error: 'connection show': %s"), error->message);
- g_error_free (error);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'connection show': %s"),
+ error->message);
return FALSE;
}
- g_assert (print_settings_array);
+
+ nm_assert (print_settings_array);
/* Main header */
{
@@ -1417,10 +1409,6 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc)
}
}
- g_array_free (print_settings_array, TRUE);
- if (prop_array)
- g_ptr_array_free (prop_array, TRUE);
-
return TRUE;
}
@@ -1440,9 +1428,9 @@ nmc_active_connection_state_to_color (NMActiveConnectionState state)
static gboolean
nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
{
- GError *error = NULL;
- GArray *print_groups;
- GPtrArray *group_fields = NULL;
+ gs_free_error GError *error = NULL;
+ gs_unref_array GArray *print_groups = NULL;
+ gs_unref_ptrarray GPtrArray *group_fields = NULL;
int i;
const char *fields_str = NULL;
const char *base_hdr = _("Activate connection details");
@@ -1455,12 +1443,14 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
print_groups = parse_output_fields (fields_str, (const NMMetaAbstractInfo *const*) nmc_fields_con_active_details_groups, TRUE, &group_fields, &error);
if (error) {
- g_string_printf (nmc->return_text, _("Error: 'connection show': %s"), error->message);
- g_error_free (error);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'connection show': %s"),
+ error->message);
return FALSE;
}
- g_assert (print_groups);
+
+ nm_assert (print_groups);
/* Main header */
{
@@ -1489,7 +1479,7 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
/* Loop through the groups and print them. */
for (i = 0; i < print_groups->len; i++) {
int group_idx = g_array_index (print_groups, int, i);
- char *group_fld = (char *) g_ptr_array_index (group_fields, i);
+ char *group_fld = g_ptr_array_index (group_fields, i);
if ( NM_IN_SET (nmc->nmc_config.print_output, NMC_PRINT_NORMAL, NMC_PRINT_PRETTY)
&& !nmc->nmc_config.multiline_output
@@ -1566,10 +1556,6 @@ nmc_active_connection_details (NMActiveConnection *acon, NmCli *nmc)
}
}
- g_array_free (print_groups, TRUE);
- if (group_fields)
- g_ptr_array_free (group_fields, TRUE);
-
return TRUE;
}
@@ -1976,7 +1962,7 @@ parse_preferred_connection_order (const char *order, GError **error)
static NMConnection *
get_connection (NmCli *nmc,
int *argc,
- char ***argv,
+ const char *const**argv,
const char **out_selector,
const char **out_value,
GPtrArray **out_result,
@@ -2027,8 +2013,8 @@ get_connection (NmCli *nmc,
return connection;
}
-static NMCResultCode
-do_connections_show (NmCli *nmc, int argc, char **argv)
+static void
+do_connections_show (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
gs_free_error GError *err = NULL;
gs_free char *profile_flds = NULL;
@@ -2132,9 +2118,10 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
/* Before printing the connections check if we have a "--show-secret"
* option after the connection ids */
- if (!nmc->nmc_config.show_secrets && !nmc->complete) {
+ if ( !nmc->nmc_config.show_secrets
+ && !nmc->complete) {
int argc_cp = argc;
- char **argv_cp = argv;
+ const char *const*argv_cp = argv;
do {
if (NM_IN_STRSET (*argv_cp, "id", "uuid", "path", "filename", "apath")) {
@@ -2162,9 +2149,11 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
argc--;
argv++;
if (!argc) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- goto finish;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: %s argument is missing."),
+ argv[-1]);
+ return;
}
}
@@ -2189,10 +2178,13 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
}
}
- if (!con && !explicit_acon) {
- g_string_printf (nmc->return_text, _("Error: %s - no such connection profile."), *argv);
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
- goto finish;
+ if ( !con
+ && !explicit_acon) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_NOT_FOUND,
+ _("Error: %s - no such connection profile."),
+ *argv);
+ return;
}
/* Print connection details:
@@ -2281,10 +2273,11 @@ do_connections_show (NmCli *nmc, int argc, char **argv)
finish:
if (err) {
- g_string_printf (nmc->return_text, _("Error: %s."), err->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: %s."),
+ err->message);
}
- return nmc->return_value;
}
static NMActiveConnection *
@@ -2453,10 +2446,11 @@ typedef struct {
NmCli *nmc;
NMDevice *device;
NMActiveConnection *active;
+ GSource *progress_source;
} ActivateConnectionInfo;
static void
-active_connection_hint (GString *return_text,
+active_connection_hint (NmcRunStatus *run_status,
NMActiveConnection *active,
NMDevice *device)
{
@@ -2488,8 +2482,7 @@ active_connection_hint (GString *return_text,
}
}
- g_string_append (return_text, "\n");
- g_string_append_printf (return_text, _("Hint: use '%s' to get more details."), hint->str);
+ nmc_run_status_return_append_message (run_status, _("Hint: use '%s' to get more details."), hint->str);
}
static void activate_connection_info_finish (ActivateConnectionInfo *info);
@@ -2515,15 +2508,16 @@ check_activated (ActivateConnectionInfo *info)
nm_object_get_path (NM_OBJECT (info->active)));
}
activate_connection_info_finish (info);
- break;
+ return;
case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
nm_assert (reason);
- g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"),
- reason);
- active_connection_hint (nmc->return_text, info->active, info->device);
- nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_CON_ACTIVATION,
+ _("Error: Connection activation failed: %s"),
+ reason);
+ active_connection_hint (&nmc->run_status, info->active, info->device);
activate_connection_info_finish (info);
- break;
+ return;
case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
if (nmc->secret_agent) {
NMRemoteConnection *connection = nm_active_connection_get_connection (info->active);
@@ -2531,7 +2525,7 @@ check_activated (ActivateConnectionInfo *info)
nm_secret_agent_simple_enable (nmc->secret_agent,
nm_connection_get_path (NM_CONNECTION (connection)));
}
- break;
+ return;
default:
break;
}
@@ -2552,32 +2546,25 @@ active_connection_state_cb (NMActiveConnection *active,
check_activated (info);
}
-static void
-set_nmc_error_timeout (NmCli *nmc)
-{
- g_string_printf (nmc->return_text, _("Error: Timeout expired (%d seconds)"), nmc->timeout);
- nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
-}
-
static gboolean
activate_connection_timeout_cb (gpointer user_data)
{
ActivateConnectionInfo *info = user_data;
+ NmCli *nmc = info->nmc;
- /* Time expired -> exit nmcli */
- set_nmc_error_timeout (info->nmc);
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_TIMEOUT_EXPIRED,
+ _("Error: Timeout expired (%d seconds)"),
+ nmc->timeout);
activate_connection_info_finish (info);
- return FALSE;
+ return G_SOURCE_REMOVE;
}
static gboolean
progress_cb (gpointer user_data)
{
- const char *str = (const char *) user_data;
-
- nmc_terminal_show_progress (str);
-
- return TRUE;
+ nmc_terminal_show_progress (_("preparing"));
+ return G_SOURCE_CONTINUE;
}
static gboolean
@@ -2596,9 +2583,8 @@ progress_active_connection_cb (gpointer user_data)
* is more interesting. */
ac_devs = nm_active_connection_get_devices (active);
device = ac_devs->len > 0 ? g_ptr_array_index (ac_devs, 0) : NULL;
- } else {
+ } else
device = NULL;
- }
str = device
? gettext (nmc_device_state_to_string (nm_device_get_state (device)))
@@ -2606,12 +2592,14 @@ progress_active_connection_cb (gpointer user_data)
nmc_terminal_show_progress (str);
- return TRUE;
+ return G_SOURCE_CONTINUE;
}
static void
activate_connection_info_finish (ActivateConnectionInfo *info)
{
+ NmCli *nmc = info->nmc;
+
if (info->device) {
g_signal_handlers_disconnect_by_func (info->device, G_CALLBACK (device_state_cb), info);
g_object_unref (info->device);
@@ -2622,8 +2610,12 @@ activate_connection_info_finish (ActivateConnectionInfo *info)
g_object_unref (info->active);
}
- g_free (info);
- quit ();
+ nm_clear_g_source_inst (&info->progress_source);
+
+ nm_g_slice_free (info);
+
+ nmc_run_status_return_success_if_necessary (&nmc->run_status);
+ nmc_run_status_wait_pop (&nmc->run_status);
}
static void
@@ -2635,58 +2627,63 @@ activate_connection_cb (GObject *client, GAsyncResult *result, gpointer user_dat
NMActiveConnection *active;
NMActiveConnectionState state;
const GPtrArray *ac_devs;
- GError *error = NULL;
+ gs_free_error GError *error = NULL;
- info->active = active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error);
+ active = nm_client_activate_connection_finish (NM_CLIENT (client), result, &error);
+ info->active = active;
if (error) {
- g_string_printf (nmc->return_text, _("Error: Connection activation failed: %s"),
- error->message);
- g_error_free (error);
- active_connection_hint (nmc->return_text, info->active, info->device);
- nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_CON_ACTIVATION,
+ _("Error: Connection activation failed: %s"),
+ error->message);
+ active_connection_hint (&nmc->run_status, info->active, info->device);
activate_connection_info_finish (info);
- } else {
- state = nm_active_connection_get_state (active);
- if (!device && !nm_active_connection_get_vpn (active)) {
- /* device could be NULL for virtual devices. Fill it here. */
- ac_devs = nm_active_connection_get_devices (active);
- device = ac_devs->len > 0 ? g_ptr_array_index (ac_devs, 0) : NULL;
- if (device)
- info->device = g_object_ref (device);
- }
+ return;
+ }
- if (nmc->nowait_flag || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
- /* User doesn't want to wait or already activated */
- if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
- if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
- nmc_terminal_erase_line ();
- g_print (_("Connection successfully activated (D-Bus active path: %s)\n"),
- nm_object_get_path (NM_OBJECT (active)));
- }
- activate_connection_info_finish (info);
- } else {
- /* Monitor the active connection and device (if available) states */
- g_signal_connect (active, "state-changed", G_CALLBACK (active_connection_state_cb), info);
- if (device)
- g_signal_connect (device, "notify::" NM_DEVICE_STATE, G_CALLBACK (device_state_cb), info);
- /* Both active_connection_state_cb () and device_state_cb () will just
- * call check_activated (info). So, just call it once directly after
- * connecting on both the signals of the objects and skip the call to
- * the callbacks.
- */
- check_activated (info);
+ state = nm_active_connection_get_state (active);
+ if (!device && !nm_active_connection_get_vpn (active)) {
+ /* device could be NULL for virtual devices. Fill it here. */
+ ac_devs = nm_active_connection_get_devices (active);
+ device = ac_devs->len > 0 ? g_ptr_array_index (ac_devs, 0) : NULL;
+ if (device)
+ info->device = g_object_ref (device);
+ }
- /* Start progress indication showing VPN states */
- if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) {
- if (progress_id)
- g_source_remove (progress_id);
- progress_id = g_timeout_add (120, progress_active_connection_cb, active);
- }
+ if (nmc->nowait_flag || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+ /* User doesn't want to wait or already activated */
+ if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+ if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
+ nmc_terminal_erase_line ();
+ g_print (_("Connection successfully activated (D-Bus active path: %s)\n"),
+ nm_object_get_path (NM_OBJECT (active)));
+ }
+ activate_connection_info_finish (info);
+ } else {
+ /* Monitor the active connection and device (if available) states */
+ g_signal_connect (active, "state-changed", G_CALLBACK (active_connection_state_cb), info);
+ if (device)
+ g_signal_connect (device, "notify::" NM_DEVICE_STATE, G_CALLBACK (device_state_cb), info);
+ /* Both active_connection_state_cb () and device_state_cb () will just
+ * call check_activated (info). So, just call it once directly after
+ * connecting on both the signals of the objects and skip the call to
+ * the callbacks.
+ */
+ check_activated (info);
- /* Start timer not to loop forever when signals are not emitted */
- g_timeout_add_seconds (nmc->timeout, activate_connection_timeout_cb, info);
+ /* Start progress indication showing VPN states */
+ if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) {
+ nmc_run_status_wait_remove_source (&nmc->run_status,
+ g_steal_pointer (&info->progress_source));
+ info->progress_source = g_source_ref (nmc_run_status_wait_add_timeout (&nmc->run_status,
+ 120,
+ progress_active_connection_cb,
+ active));
}
+
+ /* Start timer not to loop forever when signals are not emitted */
+ g_timeout_add_seconds (nmc->timeout, activate_connection_timeout_cb, info);
}
}
@@ -2783,6 +2780,7 @@ nmc_activate_connection (NmCli *nmc,
const char *nsp,
const char *pwds,
GAsyncReadyCallback callback,
+ GSource ***out_progress_source_location,
GError **error)
{
ActivateConnectionInfo *info;
@@ -2795,6 +2793,8 @@ nmc_activate_connection (NmCli *nmc,
g_return_val_if_fail (nmc, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ NM_SET_OUT (out_progress_source_location, NULL);
+
if ( connection
&& ( ifname
|| ap
@@ -2839,23 +2839,27 @@ nmc_activate_connection (NmCli *nmc,
nmc);
}
- info = g_malloc0 (sizeof (ActivateConnectionInfo));
- info->nmc = nmc;
- if (device)
- info->device = g_object_ref (device);
+ info = g_slice_new (ActivateConnectionInfo);
+ *info = (ActivateConnectionInfo) {
+ .nmc = nmc,
+ .device = nm_g_object_ref (device),
+ };
nm_client_activate_connection_async (nmc->client,
connection,
device,
spec_object,
- NULL,
+ nmc->run_status.cancellable,
callback,
info);
+
+ NM_SET_OUT (out_progress_source_location, &info->progress_source);
+
return TRUE;
}
-static NMCResultCode
-do_connection_up (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_up (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
NMConnection *connection = NULL;
const char *ifname = NULL;
@@ -2863,10 +2867,11 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
const char *nsp = NULL;
const char *pwds = NULL;
gs_free_error GError *error = NULL;
- char **arg_arr = NULL;
+ gs_strfreev char **arg_arr = NULL;
int arg_num;
- char ***argv_ptr;
+ const char *const**argv_ptr;
int *argc_ptr;
+ GSource **progress_source_location;
/*
* Set default timeout for connection activation.
@@ -2879,7 +2884,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
argv_ptr = &argv;
argc_ptr = &argc;
- if (argc == 0 && nmc->ask) {
+ if ( argc == 0
+ && nmc->ask) {
gs_free char *line = NULL;
/* nmc_do_cmd() should not call this with argc=0. */
@@ -2888,15 +2894,19 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
line = nmc_readline (&nmc->nmc_config,
PROMPT_CONNECTION);
nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
- argv_ptr = &arg_arr;
+ argv_ptr = (const char *const**) &arg_arr;
argc_ptr = &arg_num;
}
- if (argc > 0 && strcmp (*argv, "ifname") != 0) {
+ if ( argc > 0
+ && nm_streq (*argv, "ifname")) {
connection = get_connection (nmc, argc_ptr, argv_ptr, NULL, NULL, NULL, &error);
if (!connection) {
- g_string_printf (nmc->return_text, _("Error: %s."), error->message);
- return error->code;
+ nmc_run_status_return (&nmc->run_status,
+ error->code,
+ _("Error: %s."),
+ error->message);
+ return;
}
}
@@ -2908,8 +2918,11 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
argc--;
argv++;
if (!argc) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- return NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: %s argument is missing."),
+ argv[-1]);
+ return;
}
ifname = *argv;
@@ -2920,8 +2933,11 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
argc--;
argv++;
if (!argc) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- return NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: %s argument is missing."),
+ argv[-1]);
+ return;
}
ap = *argv;
@@ -2932,45 +2948,63 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
argc--;
argv++;
if (!argc) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
- return NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: %s argument is missing."),
+ argv[-1]);
+ return;
}
if (argc == 1 && nmc->complete)
- nmc->return_value = NMC_RESULT_COMPLETE_FILE;
+ nmc_run_status_set_complete_file (&nmc->run_status);
pwds = *argv;
}
else if (!nmc->complete) {
- g_string_printf (nmc->return_text, _("Error: invalid extra argument '%s'."), *argv);
- return NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: invalid extra argument '%s'."),
+ *argv);
+ return;
}
next_arg (nmc, &argc, &argv, NULL);
}
if (nmc->complete)
- return nmc->return_value;
+ return;
/* Use nowait_flag instead of should_wait because exiting has to be postponed till
* active_connection_state_cb() is called. That gives NM time to check our permissions
* and we can follow activation progress.
*/
nmc->nowait_flag = (nmc->timeout == 0);
- nmc->should_wait++;
- if (!nmc_activate_connection (nmc, connection, ifname, ap, nsp, pwds, activate_connection_cb, &error)) {
- g_string_printf (nmc->return_text, _("Error: %s."),
- error->message);
- nmc->should_wait--;
- return error->code;
+ if (!nmc_activate_connection (nmc,
+ connection,
+ ifname,
+ ap,
+ nsp,
+ pwds,
+ activate_connection_cb,
+ &progress_source_location,
+ &error)) {
+ nmc_run_status_return (&nmc->run_status,
+ error->code,
+ _("Error: %s."),
+ error->message);
+ return;
}
- /* Start progress indication */
- if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
- progress_id = g_timeout_add (120, progress_cb, _("preparing"));
+ nmc_run_status_wait_push (&nmc->run_status);
- return nmc->return_value;
+ if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) {
+ /* Start progress indication */
+ *progress_source_location = g_source_ref (nmc_run_status_wait_add_timeout (&nmc->run_status,
+ 120,
+ progress_cb,
+ NULL));
+ }
}
/*****************************************************************************/
@@ -2980,7 +3014,7 @@ typedef struct {
/* a list of object that is relevant for the callback. The object
* type differs, and depends on the type of callback. */
GPtrArray *obj_list;
- guint timeout_id;
+ GSource *timeout_source;
GCancellable *cancellable;
} ConnectionCbInfo;
@@ -3044,6 +3078,8 @@ connection_cb_info_obj_list_steal (ConnectionCbInfo *info, gpointer obj)
static void
connection_cb_info_finish (ConnectionCbInfo *info, gpointer obj)
{
+ NmCli *nmc = info->nmc;
+
if (obj) {
obj = connection_cb_info_obj_list_steal (info, obj);
if (obj)
@@ -3059,73 +3095,193 @@ connection_cb_info_finish (ConnectionCbInfo *info, gpointer obj)
if (info->obj_list->len > 0)
return;
- nm_clear_g_source (&info->timeout_id);
+ //XXX
+#if 0
+ if (info->timeout_source) {
+ nmc_run_status_wait_remove_source (nmc, g_steal_pointer (&info->timeout_source));
+ nmc_run_status_wait_pop (&nmc->run_status);
+ }
+#endif
+
nm_clear_g_cancellable (&info->cancellable);
g_ptr_array_free (info->obj_list, TRUE);
g_signal_handlers_disconnect_by_func (info->nmc->client, connection_removed_cb, info);
- g_slice_free (ConnectionCbInfo, info);
+ nm_g_slice_free (info);
- quit ();
+ nmc_run_status_return_success_if_necessary (&nmc->run_status);
+ nmc_run_status_wait_pop (&nmc->run_status);
}
/*****************************************************************************/
+struct _ConnectionDownData;
+
+typedef struct {
+ struct _ConnectionDownData *info;
+ NMActiveConnection *active;
+ char *id;
+ gulong signal_id;
+ bool done:1;
+} ConnectionDownItem;
+
+typedef struct _ConnectionDownData {
+ NmCli *nmc;
+ GSource *timeout_source;
+ char *not_found_ac;
+ char *deactivation_failure;
+ ConnectionDownItem *items;
+ guint n_items;
+ guint timeout_sec;
+} ConnectionDownData;
+
static void
-connection_removed_cb (NMClient *client, NMConnection *connection, ConnectionCbInfo *info)
+_down_connection_finish (ConnectionDownData *info)
{
- if (!connection_cb_info_obj_list_has (info, connection))
- return;
- g_print (_("Connection '%s' (%s) successfully deleted.\n"),
- nm_connection_get_id (connection),
- nm_connection_get_uuid (connection));
- connection_cb_info_finish (info, connection);
+ nm_auto_pop_run_status NmCli *nmc = info->nmc;
+ guint i;
+
+ if (!nmc_run_status_is_returned (&nmc->run_status)) {
+ if (info->not_found_ac) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_NOT_FOUND,
+ _("Error: '%s' is not an active connection."),
+ info->not_found_ac);
+ } if (info->deactivation_failure) {
+ nmc_run_status_return_message_full (&nmc->run_status,
+ NMC_RESULT_ERROR_CON_DEACTIVATION,
+ g_steal_pointer (&info->deactivation_failure));
+ } else
+ nmc_run_status_return_success (&nmc->run_status);
+ }
+
+ g_free (info->not_found_ac);
+ g_free (info->deactivation_failure);
+ for (i = 0; i < info->n_items; i++) {
+ ConnectionDownItem *item = &info->items[i];
+
+ nm_clear_g_signal_handler (item->active, &item->signal_id);
+ g_object_unref (item->active);
+ g_free (item->id);
+ }
+ g_free (info->items);
+ if (info->timeout_source)
+ nmc_run_status_wait_remove_source (&nmc->run_status, info->timeout_source);
+
+ nm_g_slice_free (info);
}
static void
-down_active_connection_state_cb (NMActiveConnection *active,
- GParamSpec *pspec,
- ConnectionCbInfo *info)
+_down_connection_check_done (ConnectionDownItem *item)
{
- if (nm_active_connection_get_state (active) < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
+ ConnectionDownData *info = item->info;
+ guint i;
+
+ if ( nm_object_get_client (NM_OBJECT (item->active))
+ && nm_active_connection_get_state (item->active) < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
return;
- if (info->nmc->nmc_config.print_output == NMC_PRINT_PRETTY)
- nmc_terminal_erase_line ();
- g_print (_("Connection '%s' successfully deactivated (D-Bus active path: %s)\n"),
- nm_active_connection_get_id (active), nm_object_get_path (NM_OBJECT (active)));
+ nm_clear_g_signal_handler (item->active, &item->signal_id);
+
+ if (!item->done) {
+ item->done = TRUE;
+ g_print (_("Connection '%s' successfully deactivated (D-Bus active path: %s)\n"),
+ item->id,
+ nm_object_get_path (NM_OBJECT (item->active)));
+ }
+
+ for (i = 0; i < info->n_items; i++) {
+ if (!info->items[i].done)
+ return;
+ }
- g_signal_handlers_disconnect_by_func (G_OBJECT (active),
- down_active_connection_state_cb,
- info);
- connection_cb_info_finish (info, active);
+ _down_connection_finish (info);
+}
+
+static void
+_down_connection_ac_state_change (NMActiveConnection *active,
+ GParamSpec *pspec,
+ ConnectionDownItem *item)
+{
+ _down_connection_check_done (item);
}
static gboolean
-connection_op_timeout_cb (gpointer user_data)
+_down_connection_timeout_cb (gpointer user_data)
{
- ConnectionCbInfo *info = user_data;
+ ConnectionDownData *info = user_data;
+ NmCli *nmc = info->nmc;
+ guint i;
- set_nmc_error_timeout (info->nmc);
- connection_cb_info_finish (info, NULL);
+ for (i = 0; i < info->n_items; i++) {
+ ConnectionDownItem *item = &info->items[i];
+
+ if (!item->done) {
+ g_print (_("Connection '%s' deactivation failed: timeout reached\n"),
+ item->id);
+ }
+ }
+
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_TIMEOUT_EXPIRED,
+ _("Error: Timeout expired (%u seconds)"),
+ info->timeout_sec);
+ _down_connection_finish (info);
return G_SOURCE_REMOVE;
}
-static NMCResultCode
-do_connection_down (NmCli *nmc, int argc, char **argv)
+static void
+_down_connection_cb (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+ nm_auto_pop_run_status NmCli *nmc = NULL;
+ ConnectionDownItem *item;
+ ConnectionDownData *info;
+ gs_free_error GError *error = NULL;
+ gboolean success;
+
+ nm_utils_user_data_unpack (user_data, &nmc, &item);
+
+ success = nm_client_deactivate_connection_finish (nmc->client,
+ result,
+ &error);
+
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
+ item = user_data;
+ info = item->info;
+
+ if (!success) {
+ item->done = TRUE;
+
+ g_print (_("Connection '%s' deactivation failed: %s\n"),
+ item->id, error->message);
+
+ if (!info->deactivation_failure)
+ info->deactivation_failure = g_strdup_printf (_("Failure to deactivate connect '%s'"), item->id);
+ } else {
+ item->signal_id = g_signal_connect (item->active,
+ "notify::" NM_ACTIVE_CONNECTION_STATE,
+ G_CALLBACK (_down_connection_ac_state_change),
+ item);
+ }
+
+ _down_connection_check_done (item);
+}
+
+static void
+do_connection_down (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
NMActiveConnection *active;
- ConnectionCbInfo *info = NULL;
const GPtrArray *active_cons;
gs_strfreev char **arg_arr = NULL;
- char **arg_ptr;
+ const char *const*arg_ptr;
int arg_num;
guint i;
gs_unref_ptrarray GPtrArray *found_active_cons = NULL;
-
- if (nmc->timeout == -1)
- nmc->timeout = 10;
+ const char *not_found_ac = NULL;
+ ConnectionDownData *info;
next_arg (nmc, &argc, &argv, NULL);
arg_ptr = argv;
@@ -3141,11 +3297,13 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
line = nmc_readline (&nmc->nmc_config,
PROMPT_ACTIVE_CONNECTIONS);
nmc_string_to_arg_array (line, NULL, TRUE, &arg_arr, &arg_num);
- arg_ptr = arg_arr;
+ arg_ptr = (const char *const*) arg_arr;
}
if (arg_num == 0) {
- g_string_printf (nmc->return_text, _("Error: No connection specified."));
- return NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: No connection specified."));
+ return;
}
}
@@ -3162,8 +3320,11 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
arg_num--;
arg_ptr++;
if (!arg_num) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), selector);
- return NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: %s argument is missing."),
+ selector);
+ return;
}
}
@@ -3175,59 +3336,63 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
if (!active) {
if (!nmc->complete)
g_printerr (_("Error: '%s' is not an active connection.\n"), *arg_ptr);
- g_string_printf (nmc->return_text, _("Error: not all active connections found."));
- nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
+ if (!not_found_ac)
+ not_found_ac = *arg_ptr;
}
next_arg (nmc->ask ? NULL : nmc, &arg_num, &arg_ptr, NULL);
}
if (!found_active_cons) {
- g_string_printf (nmc->return_text, _("Error: no active connection provided."));
- return NMC_RESULT_ERROR_NOT_FOUND;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_NOT_FOUND,
+ _("Error: no active connection provided."));
+ return;
}
+
nm_assert (found_active_cons->len > 0);
if (nmc->complete)
- return nmc->return_value;
+ return;
- if (nmc->timeout > 0) {
- nmc->should_wait++;
+ nmc_run_status_wait_push (&nmc->run_status);
- info = g_slice_new0 (ConnectionCbInfo);
- info->nmc = nmc;
- info->obj_list = g_ptr_array_sized_new (found_active_cons->len);
- for (i = 0; i < found_active_cons->len; i++) {
- active = found_active_cons->pdata[i];
- g_ptr_array_add (info->obj_list, g_object_ref (active));
- g_signal_connect (active,
- "notify::" NM_ACTIVE_CONNECTION_STATE,
- G_CALLBACK (down_active_connection_state_cb),
- info);
- }
- info->timeout_id = g_timeout_add_seconds (nmc->timeout, connection_op_timeout_cb, info);
+ info = g_slice_new (ConnectionDownData);
+ *info = (ConnectionDownData) {
+ .nmc = nmc,
+ .not_found_ac = g_strdup (not_found_ac),
+ .timeout_sec = nmc->timeout == -1
+ ? 10u
+ : nmc->timeout,
+ };
+
+ if ( info->timeout_sec != 0u
+ && info->timeout_sec < G_MAXUINT / 1000u) {
+ info->timeout_source = g_source_ref (nmc_run_status_wait_add_timeout (&nmc->run_status,
+ info->timeout_sec * 1000u,
+ _down_connection_timeout_cb,
+ info));
}
+ info->items = g_new (ConnectionDownItem, found_active_cons->len);
+ info->n_items = found_active_cons->len;
+
for (i = 0; i < found_active_cons->len; i++) {
- GError *error = NULL;
+ ConnectionDownItem *item = &info->items[i];
- active = found_active_cons->pdata[i];
+ *item = (ConnectionDownItem) {
+ .info = info,
+ .active = g_object_ref (found_active_cons->pdata[i]),
+ .id = g_strdup (nm_active_connection_get_id (active) ?: "???"),
+ };
- if (!nm_client_deactivate_connection (nmc->client, active, NULL, &error)) {
- g_print (_("Connection '%s' deactivation failed: %s\n"),
- nm_active_connection_get_id (active), error->message);
- g_clear_error (&error);
-
- if (info) {
- g_signal_handlers_disconnect_by_func (active,
- down_active_connection_state_cb,
- info);
- connection_cb_info_finish (info, active);
- }
- }
+ nmc_run_status_wait_push (&nmc->run_status);
+ nm_client_deactivate_connection_async (nmc->client,
+ active,
+ nmc->run_status.cancellable,
+ _down_connection_cb,
+ nm_utils_user_data_pack (nmc, item));
}
-
- return nmc->return_value;
}
/*****************************************************************************/
@@ -3715,7 +3880,10 @@ prompt_yes_no (gboolean default_yes, char *delim)
}
static NMSetting *
-is_setting_valid (NMConnection *connection, const NMMetaSettingValidPartItem *const*valid_settings_main, const NMMetaSettingValidPartItem *const*valid_settings_slave, char *setting)
+is_setting_valid (NMConnection *connection,
+ const NMMetaSettingValidPartItem *const*valid_settings_main,
+ const NMMetaSettingValidPartItem *const*valid_settings_slave,
+ const char *setting)
{
const char *setting_name;
@@ -4656,7 +4824,7 @@ complete_option (NmCli *nmc, const NMMetaAbstractInfo *abstract_info, const char
&complete_filename,
&values_to_free);
if (complete_filename) {
- nmc->return_value = NMC_RESULT_COMPLETE_FILE;
+ nmc_run_status_set_complete_file (&nmc->run_status);
return TRUE;
}
if (values) {
@@ -4726,7 +4894,7 @@ connection_remove_setting (NMConnection *connection, NMSetting *setting, GError
}
static gboolean
-get_value (const char **value, int *argc, char ***argv, const char *option, GError **error)
+get_value (const char **value, int *argc, const char *const**argv, const char *option, GError **error)
{
if (!**argv) {
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
@@ -4749,7 +4917,7 @@ gboolean
nmc_process_connection_properties (NmCli *nmc,
NMConnection *connection,
int *argc,
- char ***argv,
+ const char *const**argv,
gboolean allow_setting_removal,
GError **error)
{
@@ -4789,7 +4957,7 @@ nmc_process_connection_properties (NmCli *nmc,
&& modifier == NM_META_ACCESSOR_MODIFIER_SET
&& nm_streq (option, "remove")) {
NMSetting *ss;
- char *setting_name;
+ const char *setting_name;
(*argc)--;
(*argv)++;
@@ -4961,49 +5129,48 @@ add_connection_cb (GObject *client,
gpointer user_data)
{
nm_auto_free_add_connection_info AddConnectionInfo *info = user_data;
- NmCli *nmc = info->nmc;
- NMRemoteConnection *connection;
- GError *error = NULL;
+ nm_auto_pop_run_status NmCli *nmc = info->nmc;
+ gs_unref_object NMRemoteConnection *connection = NULL;
+ gs_free_error GError *error = NULL;
const GPtrArray *connections;
guint i, found;
connection = nm_client_add_connection2_finish (NM_CLIENT (client), result, NULL, &error);
if (error) {
- g_string_printf (nmc->return_text,
- _("Error: Failed to add '%s' connection: %s"),
- info->new_id, error->message);
- g_error_free (error);
- nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
- } else {
- connections = nm_client_get_connections (nmc->client);
- if (connections) {
- found = 0;
- for (i = 0; i < connections->len; i++) {
- NMConnection *candidate = NM_CONNECTION (connections->pdata[i]);
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_CON_ACTIVATION,
+ _("Error: Failed to add '%s' connection: %s"),
+ info->new_id,
+ error->message);
+ return;
+ }
- if ((NMConnection *) connection == candidate)
- continue;
- if (nm_streq0 (nm_connection_get_id (candidate), info->new_id))
- found++;
- }
- if (found > 0) {
- g_printerr (g_dngettext (GETTEXT_PACKAGE,
- "Warning: There is another connection with the name '%1$s'. Reference the connection by its uuid '%2$s'\n",
- "Warning: There are %3$u other connections with the name '%1$s'. Reference the connection by its uuid '%2$s'\n",
- found),
- info->new_id,
- nm_connection_get_uuid (NM_CONNECTION (connection)),
- found);
- }
- }
+ connections = nm_client_get_connections (nmc->client);
+ if (connections) {
+ found = 0;
+ for (i = 0; i < connections->len; i++) {
+ NMConnection *candidate = NM_CONNECTION (connections->pdata[i]);
- g_print (_("Connection '%s' (%s) successfully added.\n"),
- nm_connection_get_id (NM_CONNECTION (connection)),
- nm_connection_get_uuid (NM_CONNECTION (connection)));
- g_object_unref (connection);
+ if ((NMConnection *) connection == candidate)
+ continue;
+ if (nm_streq0 (nm_connection_get_id (candidate), info->new_id))
+ found++;
+ }
+ if (found > 0) {
+ g_printerr (g_dngettext (GETTEXT_PACKAGE,
+ "Warning: There is another connection with the name '%1$s'. Reference the connection by its uuid '%2$s'\n",
+ "Warning: There are %3$u other connections with the name '%1$s'. Reference the connection by its uuid '%2$s'\n",
+ found),
+ info->new_id,
+ nm_connection_get_uuid (NM_CONNECTION (connection)),
+ found);
+ }
}
- quit ();
+ g_print (_("Connection '%s' (%s) successfully added.\n"),
+ nm_connection_get_id (NM_CONNECTION (connection)),
+ nm_connection_get_uuid (NM_CONNECTION (connection)));
+ nmc_run_status_return_success (&nmc->run_status);
}
static void
@@ -5348,8 +5515,8 @@ again:
return TRUE;
}
-static NMCResultCode
-do_connection_add (NmCli *nmc, int argc, char **argv)
+static void
+do_connection_add (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
gs_unref_object NMConnection *connection = NULL;
NMSettingConnection *s_con;
@@ -5362,8 +5529,6 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
rl_attempted_completion_function = nmcli_con_add_tab_completion;
- nmc->return_value = NMC_RESULT_SUCCESS;
-
connection = nm_simple_connection_new ();
s_con = (NMSettingConnection *) nm_setting_connection_new ();
@@ -5372,7 +5537,8 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
read_properties:
g_clear_error (&error);
/* Get the arguments from the command line if any */
- if (argc && !nmc_process_connection_properties (nmc, connection, &argc, &argv, FALSE, &error)) {
+ if ( argc
+ && !nmc_process_connection_properties (nmc, connection, &argc, &argv, FALSE, &error)) {
if (g_strcmp0 (*argv, "--") == 0 && !seen_dash_dash) {
/* This is for compatibility with older nmcli that required
* options and properties to be separated with "--" */
@@ -5385,25 +5551,27 @@ read_properties:
argc--;
argv++;
if (!argc) {
- g_string_printf (nmc->return_text,
- _("Error: value for '%s' argument is required."),
- "save");
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: value for '%s' argument is required."),
+ "save");
goto finish;
}
g_clear_error (&error);
if (!nmc_string_to_bool (*argv, &save_bool, &error)) {
- g_string_printf (nmc->return_text, _("Error: 'save': %s."),
- error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'save': %s."),
+ error->message);
goto finish;
}
next_arg (nmc, &argc, &argv, NULL);
goto read_properties;
}
- g_string_assign (nmc->return_text, error->message);
- nmc->return_value = error->code;
+ nmc_run_status_return_message (&nmc->run_status,
+ error->code,
+ error->message);
goto finish;
}
@@ -5478,8 +5646,10 @@ read_properties:
if (!option_relevant (connection, (const NMMetaAbstractInfo *) bi))
continue;
if (bi->base.inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) {
- g_string_printf (nmc->return_text, _("Error: '%s' argument is required."), bi->base.property_alias);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '%s' argument is required."),
+ bi->base.property_alias);
goto finish;
}
}
@@ -5489,24 +5659,25 @@ read_properties:
if (!option_relevant (connection, (const NMMetaAbstractInfo *) property_info))
continue;
if (property_info->inf_flags & NM_META_PROPERTY_INF_FLAG_REQD) {
- g_string_printf (nmc->return_text, _("Error: '%s' argument is required."), property_info->property_alias);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '%s' argument is required."),
+ property_info->property_alias);
goto finish;
}
}
}
}
+ nmc_run_status_wait_push (&nmc->run_status);
add_connection (nmc->client,
connection,
!save_bool,
add_connection_cb,
_add_connection_info_new (nmc, NULL, connection));
- nmc->should_wait++;
finish:
reset_options ();
- return nmc->return_value;
}
/*****************************************************************************/
@@ -8113,8 +8284,15 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
nmc->nowait_flag = FALSE;
nmc->should_wait++;
nmc->nmc_config_mutable.print_output = NMC_PRINT_PRETTY;
- if (!nmc_activate_connection (nmc, NM_CONNECTION (rem_con), ifname, ap_nsp, ap_nsp, NULL,
- activate_connection_editor_cb, &tmp_err)) {
+ if (!nmc_activate_connection (nmc,
+ NM_CONNECTION (rem_con),
+ ifname,
+ ap_nsp,
+ ap_nsp,
+ NULL,
+ activate_connection_editor_cb,
+ NULL,
+ &tmp_err)) {
g_print (_("Error: Cannot activate connection: %s.\n"), tmp_err->message);
g_clear_error (&tmp_err);
break;
@@ -8744,6 +8922,31 @@ delete_cb (GObject *con, GAsyncResult *result, gpointer user_data)
}
}
+static gboolean
+connection_op_timeout_cb (gpointer user_data)
+{
+ ConnectionCbInfo *info = user_data;
+ NmCli *nmc = info->nmc;
+
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_TIMEOUT_EXPIRED,
+ _("Error: Timeout expired (%d seconds)"),
+ nmc->timeout);
+ connection_cb_info_finish (info, NULL);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+connection_removed_cb (NMClient *client, NMConnection *connection, ConnectionCbInfo *info)
+{
+ if (!connection_cb_info_obj_list_has (info, connection))
+ return;
+ g_print (_("Connection '%s' (%s) successfully deleted.\n"),
+ nm_connection_get_id (connection),
+ nm_connection_get_uuid (connection));
+ connection_cb_info_finish (info, connection);
+}
+
static NMCResultCode
do_connection_delete (NmCli *nmc, int argc, char **argv)
{
@@ -9053,7 +9256,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
argc--;
argv++;
if (!argc) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), argv[-1]);
return NMC_RESULT_ERROR_USER_INPUT;
}
@@ -9074,7 +9277,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
argc--;
argv++;
if (!argc) {
- g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
+ g_string_printf (nmc->return_text, _("Error: %s argument is missing."), argv[-1]);
return NMC_RESULT_ERROR_USER_INPUT;
}
if (argc == 1 && nmc->complete)
@@ -9129,14 +9332,12 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
return NMC_RESULT_ERROR_UNKNOWN;
}
+ nmc_run_status_wait_push (&nmc->run_status);
add_connection (nmc->client,
connection,
temporary,
add_connection_cb,
_add_connection_info_new (nmc, NULL, connection));
- nmc->should_wait++;
-
- return nmc->return_value;
}
static NMCResultCode
@@ -9343,20 +9544,20 @@ nmcli_con_tab_completion (const char *text, int start, int end)
}
static const NMCCommand connection_cmds[] = {
- { "show", do_connections_show, usage_connection_show, TRUE, TRUE },
- { "up", do_connection_up, usage_connection_up, TRUE, TRUE },
- { "down", do_connection_down, usage_connection_down, TRUE, TRUE },
- { "add", do_connection_add, usage_connection_add, TRUE, TRUE },
- { "edit", do_connection_edit, usage_connection_edit, TRUE, TRUE },
- { "delete", do_connection_delete, usage_connection_delete, TRUE, TRUE },
- { "reload", do_connection_reload, usage_connection_reload, FALSE, FALSE },
- { "load", do_connection_load, usage_connection_load, TRUE, TRUE },
- { "modify", do_connection_modify, usage_connection_modify, TRUE, TRUE },
- { "clone", do_connection_clone, usage_connection_clone, TRUE, TRUE },
- { "import", do_connection_import, usage_connection_import, TRUE, TRUE },
- { "export", do_connection_export, usage_connection_export, TRUE, TRUE },
- { "monitor", do_connection_monitor, usage_connection_monitor, TRUE, TRUE },
- { NULL, do_connections_show, usage, TRUE, TRUE },
+ { "show", do_connections_show, usage_connection_show, TRUE, TRUE },
+ { "up", do_connection_up, usage_connection_up, TRUE, TRUE },
+ { "down", do_connection_down, usage_connection_down, TRUE, TRUE },
+ { "add", do_connection_add, usage_connection_add, TRUE, TRUE },
+ { "edit", do_connection_edit, usage_connection_edit, TRUE, TRUE },
+ { "delete", do_connection_delete, usage_connection_delete, TRUE, TRUE },
+ { "reload", do_connection_reload, usage_connection_reload, FALSE, FALSE },
+ { "load", do_connection_load, usage_connection_load, TRUE, TRUE },
+ { "modify", do_connection_modify, usage_connection_modify, TRUE, TRUE },
+ { "clone", do_connection_clone, usage_connection_clone, TRUE, TRUE },
+ { "import", do_connection_import, usage_connection_import, TRUE, TRUE },
+ { "export", do_connection_export, usage_connection_export, TRUE, TRUE },
+ { "monitor", do_connection_monitor, usage_connection_monitor, TRUE, TRUE },
+ { NULL, do_connections_show, usage, TRUE, TRUE },
};
/* Entry point function for connections-related commands: 'nmcli connection' */
diff --git a/clients/cli/connections.h b/clients/cli/connections.h
index b419ba9c00..bfc2a4f908 100644
--- a/clients/cli/connections.h
+++ b/clients/cli/connections.h
@@ -16,7 +16,7 @@ gboolean
nmc_process_connection_properties (NmCli *nmc,
NMConnection *connection,
int *argc,
- char ***argv,
+ const char *const**argv,
gboolean allow_remove_setting,
GError **error);
diff --git a/clients/cli/general.c b/clients/cli/general.c
index 6e7410ed20..05f37678ca 100644
--- a/clients/cli/general.c
+++ b/clients/cli/general.c
@@ -5,8 +5,6 @@
#include "nm-default.h"
-#include "general.h"
-
#include <stdlib.h>
#include "nm-libnm-core-intern/nm-common-macros.h"
@@ -457,12 +455,6 @@ usage_monitor (void)
}
static void
-quit (void)
-{
- g_main_loop_quit (loop);
-}
-
-static gboolean
show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_flds)
{
gs_free_error GError *error = NULL;
@@ -484,43 +476,43 @@ show_nm_status (NmCli *nmc, const char *pretty_header_name, const char *print_fl
(const NMMetaAbstractInfo *const*) metagen_general_status,
fields_str,
&error)) {
- g_string_printf (nmc->return_text, _("Error: only these fields are allowed: %s"), fields_all);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: only these fields are allowed: %s"),
+ fields_all);
}
- return TRUE;
}
-static NMCResultCode
-do_general_status (NmCli *nmc, int argc, char **argv)
+static void
+do_general_status (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
next_arg (nmc, &argc, &argv, NULL);
if (nmc->complete)
- return nmc->return_value;
+ return;
show_nm_status (nmc, NULL, NULL);
- return nmc->return_value;
}
static gboolean
timeout_cb (gpointer user_data)
{
- NmCli *nmc = (NmCli *) user_data;
+ nm_auto_pop_run_status NmCli *nmc = user_data;
g_signal_handlers_disconnect_by_func (nmc->client,
G_CALLBACK (permission_changed),
nmc);
- g_string_printf (nmc->return_text, _("Error: Timeout %d sec expired."), nmc->timeout);
- nmc->return_value = NMC_RESULT_ERROR_TIMEOUT_EXPIRED;
- quit ();
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_TIMEOUT_EXPIRED,
+ _("Error: Timeout %d sec expired."),
+ nmc->timeout);
+ return G_SOURCE_REMOVE;
}
static void
-print_permissions (void *user_data)
+print_permissions (NmCli *nmc)
{
- NmCli *nmc = user_data;
+ nm_auto_pop_run_status NmCli *nmc_pop_run_status = NULL;
gs_free_error GError *error = NULL;
const char *fields_str = NULL;
gpointer permissions[G_N_ELEMENTS (nm_auth_permission_sorted) + 1];
@@ -539,11 +531,13 @@ print_permissions (void *user_data)
G_CALLBACK (permission_changed),
nmc);
+ nmc_pop_run_status = nmc;
+
if (!is_running) {
/* NetworkManager quit while we were waiting. */
- g_string_printf (nmc->return_text, _("NetworkManager is not running."));
- nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
- quit ();
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_NM_NOT_RUNNING,
+ _("NetworkManager is not running."));
return;
}
@@ -565,11 +559,11 @@ print_permissions (void *user_data)
(const NMMetaAbstractInfo *const*) metagen_general_permissions,
fields_str,
&error)) {
- g_string_printf (nmc->return_text, _("Error: 'general permissions': %s"), error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'general permissions': %s"),
+ error->message);
}
-
- quit ();
}
static void
@@ -582,36 +576,8 @@ permission_changed (GObject *gobject,
print_permissions (nmc);
}
-static gboolean
-show_nm_permissions (NmCli *nmc)
-{
- NMClientInstanceFlags instance_flags;
-
- instance_flags = nm_client_get_instance_flags (nmc->client);
- instance_flags &= ~NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS;
-
- g_object_set (nmc->client,
- NM_CLIENT_INSTANCE_FLAGS, (guint) instance_flags,
- NULL);
-
- g_signal_connect (nmc->client,
- "notify",
- G_CALLBACK (permission_changed),
- nmc);
-
- if (nmc->timeout == -1)
- nmc->timeout = 10;
- g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
-
- nmc->should_wait++;
-
- print_permissions (nmc);
-
- return TRUE;
-}
-
-static NMCResultCode
-do_general_reload (NmCli *nmc, int argc, char **argv)
+static void
+do_general_reload (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
gs_unref_variant GVariant *result = NULL;
gs_free_error GError *error = NULL;
@@ -624,7 +590,7 @@ do_general_reload (NmCli *nmc, int argc, char **argv)
if (nmc->complete) {
if (argc == 0)
- return nmc->return_value;
+ return;
if (argc == 1) {
values = nm_utils_enum_get_values (nm_manager_reload_flags_get_type (),
@@ -632,7 +598,7 @@ do_general_reload (NmCli *nmc, int argc, char **argv)
NM_MANAGER_RELOAD_FLAG_ALL);
nmc_complete_strv (*argv, -1, values);
}
- return nmc->return_value;
+ return;
}
if (argc > 0) {
@@ -641,21 +607,26 @@ do_general_reload (NmCli *nmc, int argc, char **argv)
NM_MANAGER_RELOAD_FLAG_CONF,
NM_MANAGER_RELOAD_FLAG_ALL);
joined = g_strjoinv (",", (char **) values);
- g_string_printf (nmc->return_text,
- _("Error: invalid reload flag '%s'. Allowed flags are: %s"),
- err_token,
- joined);
- return NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: invalid reload flag '%s'. Allowed flags are: %s"),
+ err_token,
+ joined);
+ return;
}
argc--;
argv++;
}
if (argc > 0) {
- g_string_printf (nmc->return_text, _("Error: extra argument '%s'"), *argv);
- return NMC_RESULT_ERROR_USER_INPUT;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: extra argument '%s'"),
+ *argv);
+ return;
}
+ /* FIXME(cli-sync) */
result = nmc_dbus_call_sync (nmc,
"/org/freedesktop/NetworkManager",
"org.freedesktop.NetworkManager",
@@ -665,53 +636,45 @@ do_general_reload (NmCli *nmc, int argc, char **argv)
&error);
if (error) {
- g_string_printf (nmc->return_text,
- _("Error: failed to reload: %s"),
- nmc_error_get_simple_message (error));
- return NMC_RESULT_ERROR_UNKNOWN;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_UNKNOWN,
+ _("Error: failed to reload: %s"),
+ nmc_error_get_simple_message (error));
+ return;
}
-
- return nmc->return_value;
}
-static NMCResultCode
-do_general_permissions (NmCli *nmc, int argc, char **argv)
+static void
+do_general_permissions (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
+ NMClientInstanceFlags instance_flags;
+
next_arg (nmc, &argc, &argv, NULL);
if (nmc->complete)
- return nmc->return_value;
+ return;
- show_nm_permissions (nmc);
- return nmc->return_value;
-}
+ instance_flags = nm_client_get_instance_flags (nmc->client);
+ instance_flags &= ~NM_CLIENT_INSTANCE_FLAGS_NO_AUTO_FETCH_PERMISSIONS;
-static void
-show_general_logging (NmCli *nmc)
-{
- gs_free char *level_cache = NULL;
- gs_free char *domains_cache = NULL;
- gs_free_error GError *error = NULL;
- const char *fields_str = NULL;
- GetGeneralLoggingData d = {
- .level = &level_cache,
- .domains = &domains_cache,
- };
+ g_object_set (nmc->client,
+ NM_CLIENT_INSTANCE_FLAGS, (guint) instance_flags,
+ NULL);
- if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) {
- } else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
- } else
- fields_str = nmc->required_fields;
+ g_signal_connect (nmc->client,
+ "notify",
+ G_CALLBACK (permission_changed),
+ nmc);
- if (!nmc_print (&nmc->nmc_config,
- (gpointer const []) { &d, NULL },
- NULL,
- _("NetworkManager logging"),
- (const NMMetaAbstractInfo *const*) metagen_general_logging,
- fields_str,
- &error)) {
- g_string_printf (nmc->return_text, _("Error: 'general logging': %s"), error->message);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- }
+ nmc_run_status_wait_add_timeout (&nmc->run_status,
+ nmc->timeout == -1
+ ? 10
+ : nmc->timeout,
+ timeout_cb,
+ nmc);
+
+ nmc_run_status_wait_push (&nmc->run_status);
+
+ print_permissions (nmc);
}
static void
@@ -734,237 +697,283 @@ nmc_complete_strings_nocase (const char *prefix, ...)
static void
_set_logging_cb (GObject *object, GAsyncResult *result, gpointer user_data)
{
- NmCli *nmc = user_data;
+ nm_auto_pop_run_status NmCli *nmc = user_data;
gs_unref_variant GVariant *res = NULL;
gs_free_error GError *error = NULL;
res = nm_client_dbus_call_finish (NM_CLIENT (object), result, &error);
if (!res) {
+ if (nm_utils_error_is_cancelled (error))
+ return;
g_dbus_error_strip_remote_error (error);
- g_string_printf (nmc->return_text, _("Error: failed to set logging: %s"),
- nmc_error_get_simple_message (error));
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_UNKNOWN,
+ _("Error: failed to set logging: %s"),
+ nmc_error_get_simple_message (error));
}
- quit ();
}
-static NMCResultCode
-do_general_logging (NmCli *nmc, int argc, char **argv)
+static void
+do_general_logging (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
+ const char *level = NULL;
+ const char *domains = NULL;
+
next_arg (nmc, &argc, &argv, NULL);
+
if (argc == 0) {
+ gs_free char *level_cache = NULL;
+ gs_free char *domains_cache = NULL;
+ gs_free_error GError *error = NULL;
+ const char *fields_str = NULL;
+ GetGeneralLoggingData d = {
+ .level = &level_cache,
+ .domains = &domains_cache,
+ };
+
if (nmc->complete)
- return nmc->return_value;
+ return;
- show_general_logging (nmc);
- } else {
- /* arguments provided -> set logging level and domains */
- const char *level = NULL;
- const char *domains = NULL;
-
- do {
- if (argc == 1 && nmc->complete)
- nmc_complete_strings (*argv, "level", "domains");
-
- if (matches (*argv, "level")) {
- argc--;
- argv++;
- if (!argc) {
- g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1));
- return NMC_RESULT_ERROR_USER_INPUT;
- }
- if (argc == 1 && nmc->complete) {
- nmc_complete_strings_nocase (*argv, "TRACE", "DEBUG", "INFO", "WARN",
- "ERR", "OFF", "KEEP", NULL);
- }
- level = *argv;
- } else if (matches (*argv, "domains")) {
- argc--;
- argv++;
- if (!argc) {
- g_string_printf (nmc->return_text, _("Error: '%s' argument is missing."), *(argv-1));
- return NMC_RESULT_ERROR_USER_INPUT;
- }
- if (argc == 1 && nmc->complete) {
- nmc_complete_strings_nocase (*argv, "PLATFORM", "RFKILL", "ETHER", "WIFI", "BT",
- "MB", "DHCP4", "DHCP6", "PPP", "WIFI_SCAN", "IP4",
- "IP6", "AUTOIP4", "DNS", "VPN", "SHARING", "SUPPLICANT",
- "AGENTS", "SETTINGS", "SUSPEND", "CORE", "DEVICE", "OLPC",
- "INFINIBAND", "FIREWALL", "ADSL", "BOND", "VLAN", "BRIDGE",
- "DBUS_PROPS", "TEAM", "CONCHECK", "DCB", "DISPATCH", "AUDIT",
- "SYSTEMD", "VPN_PLUGIN", "PROXY", "TC", NULL);
- }
- domains = *argv;
- } else {
- g_string_printf (nmc->return_text, _("Error: property '%s' is not known."), *argv);
- return NMC_RESULT_ERROR_USER_INPUT;
+ if (!nmc->required_fields || g_ascii_strcasecmp (nmc->required_fields, "common") == 0) {
+ } else if (g_ascii_strcasecmp (nmc->required_fields, "all") == 0) {
+ } else
+ fields_str = nmc->required_fields;
+
+ if (!nmc_print (&nmc->nmc_config,
+ (gpointer const []) { &d, NULL },
+ NULL,
+ _("NetworkManager logging"),
+ (const NMMetaAbstractInfo *const*) metagen_general_logging,
+ fields_str,
+ &error)) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'general logging': %s"),
+ error->message);
+ }
+ return;
+ }
+
+ /* arguments provided -> set logging level and domains */
+ do {
+ if (argc == 1 && nmc->complete)
+ nmc_complete_strings (*argv, "level", "domains");
+
+ if (matches (*argv, "level")) {
+ argc--;
+ argv++;
+ if (!argc) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '%s' argument is missing."),
+ argv[-1]);
+ return;
}
- } while (next_arg (nmc, &argc, &argv, NULL) == 0);
+ if (argc == 1 && nmc->complete) {
+ nmc_complete_strings_nocase (*argv, "TRACE", "DEBUG", "INFO", "WARN",
+ "ERR", "OFF", "KEEP", NULL);
+ }
+ level = *argv;
+ continue;
+ }
- if (nmc->complete)
- return nmc->return_value;
-
- nmc->should_wait++;
- nm_client_dbus_call (nmc->client,
- NM_DBUS_PATH,
- NM_DBUS_INTERFACE,
- "SetLogging",
- g_variant_new ("(ss)",
- level ?: "",
- domains ?: ""),
- G_VARIANT_TYPE ("()"),
- -1,
- NULL,
- _set_logging_cb,
- nmc);
- }
+ if (matches (*argv, "domains")) {
+ argc--;
+ argv++;
+ if (!argc) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '%s' argument is missing."),
+ argv[-1]);
+ return;
+ }
+ if (argc == 1 && nmc->complete) {
+ nmc_complete_strings_nocase (*argv, "PLATFORM", "RFKILL", "ETHER", "WIFI", "BT",
+ "MB", "DHCP4", "DHCP6", "PPP", "WIFI_SCAN", "IP4",
+ "IP6", "AUTOIP4", "DNS", "VPN", "SHARING", "SUPPLICANT",
+ "AGENTS", "SETTINGS", "SUSPEND", "CORE", "DEVICE", "OLPC",
+ "INFINIBAND", "FIREWALL", "ADSL", "BOND", "VLAN", "BRIDGE",
+ "DBUS_PROPS", "TEAM", "CONCHECK", "DCB", "DISPATCH", "AUDIT",
+ "SYSTEMD", "VPN_PLUGIN", "PROXY", "TC", NULL);
+ }
+ domains = *argv;
+ continue;
+ }
+
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: property '%s' is not known."),
+ argv[0]);
+ return;
+ } while (next_arg (nmc, &argc, &argv, NULL) == 0);
+
+ if (nmc->complete)
+ return;
- return nmc->return_value;
+ nmc_run_status_wait_push (&nmc->run_status);
+ nm_client_dbus_call (nmc->client,
+ NM_DBUS_PATH,
+ NM_DBUS_INTERFACE,
+ "SetLogging",
+ g_variant_new ("(ss)",
+ level ?: "",
+ domains ?: ""),
+ G_VARIANT_TYPE ("()"),
+ -1,
+ nmc->run_status.cancellable,
+ _set_logging_cb,
+ nmc);
}
static void
save_hostname_cb (GObject *object, GAsyncResult *result, gpointer user_data)
{
- NmCli *nmc = (NmCli *) user_data;
- GError *error = NULL;
+ nm_auto_pop_run_status NmCli *nmc = user_data;
+ gs_free_error GError *error = NULL;
nm_client_save_hostname_finish (NM_CLIENT (object), result, &error);
if (error) {
- g_string_printf (nmc->return_text, _("Error: failed to set hostname: %s"),
- error->message);
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- g_error_free (error);
+ if (nm_utils_error_is_cancelled (error))
+ return;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_UNKNOWN,
+ _("Error: failed to set hostname: %s"),
+ error->message);
}
- quit ();
}
-static NMCResultCode
-do_general_hostname (NmCli *nmc, int argc, char **argv)
+static void
+do_general_hostname (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
+ const char *hostname;
+
next_arg (nmc, &argc, &argv, NULL);
if (nmc->complete)
- return nmc->return_value;
+ return;
if (argc == 0) {
- /* no arguments -> get hostname */
- char *hostname = NULL;
-
- g_object_get (nmc->client, NM_CLIENT_HOSTNAME, &hostname, NULL);
- if (hostname)
- g_print ("%s\n", hostname);
- g_free (hostname);
- } else {
- /* hostname provided -> set it */
- const char *hostname = *argv;
+ gs_free char *h = NULL;
- if (next_arg (nmc, &argc, &argv, NULL) == 0)
- g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname);
-
- nmc->should_wait++;
- nm_client_save_hostname_async (nmc->client, hostname, NULL, save_hostname_cb, nmc);
+ g_object_get (nmc->client, NM_CLIENT_HOSTNAME, &h, NULL);
+ if (h)
+ g_print ("%s\n", h);
+ return;
}
- return nmc->return_value;
+ hostname = *argv;
+ if (next_arg (nmc, &argc, &argv, NULL) == 0)
+ g_print ("Warning: ignoring extra garbage after '%s' hostname\n", hostname);
+ nmc_run_status_wait_push (&nmc->run_status);
+ nm_client_save_hostname_async (nmc->client, hostname, nmc->run_status.cancellable, save_hostname_cb, nmc);
}
-static const NMCCommand general_cmds[] = {
- { "status", do_general_status, usage_general_status, TRUE, TRUE },
- { "hostname", do_general_hostname, usage_general_hostname, TRUE, TRUE },
- { "permissions", do_general_permissions, usage_general_permissions, TRUE, TRUE },
- { "logging", do_general_logging, usage_general_logging, TRUE, TRUE },
- { "reload", do_general_reload, usage_general_reload, FALSE, FALSE },
- { NULL, do_general_status, usage_general, TRUE, TRUE },
-};
-
-/*
- * Entry point function for general operations 'nmcli general'
- */
-NMCResultCode
-do_general (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_do_general (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
+ static const NMCCommand general_cmds[] = {
+ { "status", do_general_status, usage_general_status, TRUE, TRUE },
+ { "hostname", do_general_hostname, usage_general_hostname, TRUE, TRUE },
+ { "permissions", do_general_permissions, usage_general_permissions, TRUE, TRUE },
+ { "logging", do_general_logging, usage_general_logging, TRUE, TRUE },
+ { "reload", do_general_reload, usage_general_reload, FALSE, FALSE },
+ { NULL, do_general_status, usage_general, TRUE, TRUE },
+ };
+
next_arg (nmc, &argc, &argv, NULL);
- /* Register polkit agent */
nmc_start_polkit_agent_start_try (nmc);
nmc_do_cmd (nmc, general_cmds, *argv, argc, argv);
-
- return nmc->return_value;
}
-static gboolean
+static void
nmc_switch_show (NmCli *nmc, const char *switch_name, const char *header)
{
- g_return_val_if_fail (nmc != NULL, FALSE);
- g_return_val_if_fail (switch_name != NULL, FALSE);
-
- if (nmc->required_fields && g_ascii_strcasecmp (nmc->required_fields, switch_name) != 0) {
- g_string_printf (nmc->return_text, _("Error: '--fields' value '%s' is not valid here (allowed field: %s)"),
- nmc->required_fields, switch_name);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nm_assert (nmc);
+ nm_assert (switch_name);
+
+ if ( nmc->required_fields
+ && g_ascii_strcasecmp (nmc->required_fields, switch_name) != 0) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '--fields' value '%s' is not valid here (allowed field: %s)"),
+ nmc->required_fields,
+ switch_name);
+ return;
}
+
if (nmc->nmc_config.print_output == NMC_PRINT_NORMAL)
nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE;
if (!nmc->required_fields)
nmc->required_fields = g_strdup (switch_name);
- return show_nm_status (nmc, header, NULL);
+ show_nm_status (nmc, header, NULL);
}
static gboolean
nmc_switch_parse_on_off (NmCli *nmc, const char *arg1, const char *arg2, gboolean *res)
{
+ int v;
+
g_return_val_if_fail (nmc != NULL, FALSE);
g_return_val_if_fail (arg1 && arg2, FALSE);
g_return_val_if_fail (res != NULL, FALSE);
- if (!strcmp (arg2, "on"))
- *res = TRUE;
- else if (!strcmp (arg2, "off"))
- *res = FALSE;
- else {
- g_string_printf (nmc->return_text, _("Error: invalid '%s' argument: '%s' (use on/off)."), arg1, arg2);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+ v = _nm_utils_ascii_str_to_bool (arg2, -1);
+ if (v == -1) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: invalid '%s' argument: '%s' (use on/off)."),
+ arg1,
+ arg2);
return FALSE;
}
+ *res = v;
return TRUE;
}
static void
-_do_networking_on_off_cb (GObject *object, GAsyncResult *result, gpointer user_data)
+_do_networking_onoff_cb (GObject *object, GAsyncResult *result, gpointer user_data)
{
- NmCli *nmc = user_data;
+ nm_auto_pop_run_status NmCli *nmc = user_data;
gs_unref_variant GVariant *ret = NULL;
gs_free_error GError *error = NULL;
ret = nm_client_dbus_call_finish (NM_CLIENT (object), result, &error);
if (!ret) {
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
if (g_error_matches (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED)) {
/* This is fine. Be quiet about it. */
} else {
g_dbus_error_strip_remote_error (error);
- g_string_printf (nmc->return_text, _("Error: failed to set networking: %s"),
- nmc_error_get_simple_message (error));
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_UNKNOWN,
+ _("Error: failed to set networking: %s"),
+ nmc_error_get_simple_message (error));
}
}
- quit ();
}
-static NMCResultCode
-do_networking_on_off (NmCli *nmc, int argc, char **argv, gboolean enable)
+static void
+do_networking_onoff (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
+ gboolean enable = nm_streq (cmd->cmd, "on");
+
+ next_arg (nmc, &argc, &argv, NULL);
+
if (nmc->complete)
- return nmc->return_value;
+ return;
nmc_start_polkit_agent_start_try (nmc);
- nmc->should_wait++;
+ nmc_run_status_wait_push (&nmc->run_status);
+
nm_client_dbus_call (nmc->client,
NM_DBUS_PATH,
NM_DBUS_INTERFACE,
@@ -972,223 +981,212 @@ do_networking_on_off (NmCli *nmc, int argc, char **argv, gboolean enable)
g_variant_new ("(b)", enable),
G_VARIANT_TYPE ("()"),
-1,
- NULL,
- _do_networking_on_off_cb,
+ nmc->run_status.cancellable,
+ _do_networking_onoff_cb,
nmc);
-
- return nmc->return_value;
}
-static NMCResultCode
-do_networking_on (NmCli *nmc, int argc, char **argv)
+static void
+do_networking_connectivity (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
- next_arg (nmc, &argc, &argv, NULL);
- return do_networking_on_off (nmc, argc, argv, TRUE);
-}
+ gs_free_error GError *error = NULL;
-static NMCResultCode
-do_networking_off (NmCli *nmc, int argc, char **argv)
-{
next_arg (nmc, &argc, &argv, NULL);
- return do_networking_on_off (nmc, argc, argv, FALSE);
-}
-static NMCResultCode
-do_networking_connectivity (NmCli *nmc, int argc, char **argv)
-{
- next_arg (nmc, &argc, &argv, NULL);
if (nmc->complete) {
if (argc == 1)
nmc_complete_strings (*argv, "check");
- return nmc->return_value;
+ return;
}
if (!argc) {
/* no arguments -> get current state */
nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, N_("Connectivity"));
- } else if (matches (*argv, "check")) {
- gs_free_error GError *error = NULL;
-
- /* Register polkit agent */
- nmc_start_polkit_agent_start_try (nmc);
+ return;
+ }
- nm_client_check_connectivity (nmc->client, NULL, &error);
- if (error) {
- g_string_printf (nmc->return_text, _("Error: %s."), error->message);
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
- } else
- nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, N_("Connectivity"));
- } else {
+ if (!matches (*argv, "check")) {
usage_networking ();
- g_string_printf (nmc->return_text, _("Error: 'networking' command '%s' is not valid."), *argv);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
+
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'networking' command '%s' is not valid."),
+ *argv);
+ return;
+ }
+
+ nmc_start_polkit_agent_start_try (nmc);
+
+ /* FIXME(cli-sync) */
+ nm_client_check_connectivity (nmc->client, nmc->run_status.cancellable, &error);
+
+ if (error) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_UNKNOWN,
+ _("Error: %s."),
+ error->message);
+ return;
}
- return nmc->return_value;
+ nmc_switch_show (nmc, NMC_FIELDS_NM_CONNECTIVITY, N_("Connectivity"));
}
-static NMCResultCode
-do_networking_show (NmCli *nmc, int argc, char **argv)
+static void
+do_networking_show (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
next_arg (nmc, &argc, &argv, NULL);
+
if (nmc->complete)
- return nmc->return_value;
+ return;
nmc_switch_show (nmc, NMC_FIELDS_NM_NETWORKING, N_("Networking"));
-
- return nmc->return_value;
}
-static const NMCCommand networking_cmds[] = {
- { "on", do_networking_on, usage_networking_on, TRUE, TRUE },
- { "off", do_networking_off, usage_networking_off, TRUE, TRUE },
- { "connectivity", do_networking_connectivity, usage_networking_connectivity, TRUE, TRUE },
- { NULL, do_networking_show, usage_networking, TRUE, TRUE },
-};
-
-/*
- * Entry point function for networking commands 'nmcli networking'
- */
-NMCResultCode
-do_networking (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_do_networking (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
+ static const NMCCommand networking_cmds[] = {
+ { "on", do_networking_onoff, usage_networking_on, TRUE, TRUE },
+ { "off", do_networking_onoff, usage_networking_off, TRUE, TRUE },
+ { "connectivity", do_networking_connectivity, usage_networking_connectivity, TRUE, TRUE },
+ { NULL, do_networking_show, usage_networking, TRUE, TRUE },
+ };
+
next_arg (nmc, &argc, &argv, NULL);
nmc_do_cmd (nmc, networking_cmds, *argv, argc, argv);
-
- return nmc->return_value;
}
-static NMCResultCode
-do_radio_all (NmCli *nmc, int argc, char **argv)
+static void
+do_radio_all (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
gboolean enable_flag;
next_arg (nmc, &argc, &argv, NULL);
+
if (argc == 0) {
if (nmc->complete)
- return nmc->return_value;
+ return;
/* no argument, show all radio switches */
show_nm_status (nmc, N_("Radio switches"), NMC_FIELDS_NM_STATUS_RADIO);
- } else {
- if (nmc->complete) {
- if (argc == 1)
- nmc_complete_bool (*argv);
- return nmc->return_value;
- }
-
- if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
- return nmc->return_value;
+ return;
+ }
- nm_client_wireless_set_enabled (nmc->client, enable_flag);
- nm_client_wimax_set_enabled (nmc->client, enable_flag);
- nm_client_wwan_set_enabled (nmc->client, enable_flag);
+ if (nmc->complete) {
+ if (argc == 1)
+ nmc_complete_bool (*argv);
+ return;
}
- return nmc->return_value;
+ if (!nmc_switch_parse_on_off (nmc, argv[-1], *argv, &enable_flag))
+ return;
+
+ /* FIXME(cli-sync) */
+ nm_client_wireless_set_enabled (nmc->client, enable_flag);
+ nm_client_wimax_set_enabled (nmc->client, enable_flag);
+ nm_client_wwan_set_enabled (nmc->client, enable_flag);
}
static void
_do_radio_wifi_cb (GObject *object, GAsyncResult *result, gpointer user_data)
{
- NmCli *nmc = user_data;
+ nm_auto_pop_run_status NmCli *nmc = user_data;
gs_free_error GError *error = NULL;
if (!nm_client_dbus_set_property_finish (NM_CLIENT (object), result, &error)) {
+ if (nm_utils_error_is_cancelled (error))
+ return;
+
g_dbus_error_strip_remote_error (error);
- g_string_printf (nmc->return_text, _("Error: failed to set Wi-Fi radio: %s"),
- nmc_error_get_simple_message (error));
- nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_UNKNOWN,
+ _("Error: failed to set Wi-Fi radio: %s"),
+ nmc_error_get_simple_message (error));
}
- quit ();
}
-static NMCResultCode
-do_radio_wifi (NmCli *nmc, int argc, char **argv)
+static void
+do_radio_wifi (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
gboolean enable_flag;
next_arg (nmc, &argc, &argv, NULL);
+
if (argc == 0) {
if (nmc->complete)
- return nmc->return_value;
+ return;
/* no argument, show current Wi-Fi state */
nmc_switch_show (nmc, NMC_FIELDS_NM_WIFI, N_("Wi-Fi radio switch"));
- } else {
- if (nmc->complete) {
- if (argc == 1)
- nmc_complete_bool (*argv);
- return nmc->return_value;
- }
- if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
- return nmc->return_value;
-
- nmc_start_polkit_agent_start_try (nmc);
-
- nmc->should_wait++;
- nm_client_dbus_set_property (nmc->client,
- NM_DBUS_PATH,
- NM_DBUS_INTERFACE,
- "WirelessEnabled",
- g_variant_new_boolean (enable_flag),
- -1,
- NULL,
- _do_radio_wifi_cb,
- nmc);
+ return;
+ }
+
+ if (nmc->complete) {
+ if (argc == 1)
+ nmc_complete_bool (*argv);
+ return;
}
- return nmc->return_value;
+ if (!nmc_switch_parse_on_off (nmc, argv[-1], *argv, &enable_flag))
+ return;
+
+ nmc_start_polkit_agent_start_try (nmc);
+
+ nmc_run_status_wait_push (&nmc->run_status);
+ nm_client_dbus_set_property (nmc->client,
+ NM_DBUS_PATH,
+ NM_DBUS_INTERFACE,
+ "WirelessEnabled",
+ g_variant_new_boolean (enable_flag),
+ -1,
+ nmc->run_status.cancellable,
+ _do_radio_wifi_cb,
+ nmc);
}
-static NMCResultCode
-do_radio_wwan (NmCli *nmc, int argc, char **argv)
+static void
+do_radio_wwan (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
gboolean enable_flag;
next_arg (nmc, &argc, &argv, NULL);
if (argc == 0) {
if (nmc->complete)
- return nmc->return_value;
+ return;
/* no argument, show current WWAN (mobile broadband) state */
nmc_switch_show (nmc, NMC_FIELDS_NM_WWAN, N_("WWAN radio switch"));
- } else {
- if (nmc->complete) {
- if (argc == 1)
- nmc_complete_bool (*argv);
- return nmc->return_value;
- }
- if (!nmc_switch_parse_on_off (nmc, *(argv-1), *argv, &enable_flag))
- return nmc->return_value;
+ return;
+ }
- nm_client_wwan_set_enabled (nmc->client, enable_flag);
+ if (nmc->complete) {
+ if (argc == 1)
+ nmc_complete_bool (*argv);
+ return;
}
- return nmc->return_value;
-}
+ if (!nmc_switch_parse_on_off (nmc, argv[-1], *argv, &enable_flag))
+ return;
-static const NMCCommand radio_cmds[] = {
- { "all", do_radio_all, usage_radio_all, TRUE, TRUE },
- { "wifi", do_radio_wifi, usage_radio_wifi, TRUE, TRUE },
- { "wwan", do_radio_wwan, usage_radio_wwan, TRUE, TRUE },
- { NULL, do_radio_all, usage_radio, TRUE, TRUE },
-};
+ /* FIXME(cli-sync) */
+ nm_client_wwan_set_enabled (nmc->client, enable_flag);
+}
-/*
- * Entry point function for radio switch commands 'nmcli radio'
- */
-NMCResultCode
-do_radio (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_do_radio (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
+ static const NMCCommand radio_cmds[] = {
+ { "all", do_radio_all, usage_radio_all, TRUE, TRUE },
+ { "wifi", do_radio_wifi, usage_radio_wifi, TRUE, TRUE },
+ { "wwan", do_radio_wwan, usage_radio_wwan, TRUE, TRUE },
+ { NULL, do_radio_all, usage_radio, TRUE, TRUE },
+ };
+
next_arg (nmc, &argc, &argv, NULL);
- /* Register polkit agent */
nmc_start_polkit_agent_start_try (nmc);
nmc_do_cmd (nmc, radio_cmds, *argv, argc, argv);
-
- return nmc->return_value;
}
static void
@@ -1428,11 +1426,8 @@ ac_overview (NmCli *nmc, NMActiveConnection *ac)
g_string_free (outbuf, TRUE);
}
-/*
- * Entry point function for 'nmcli' without arguments.
- */
-NMCResultCode
-do_overview (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_do_overview (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
NMDevice **devices;
const GPtrArray *p;
@@ -1444,7 +1439,6 @@ do_overview (NmCli *nmc, int argc, char **argv)
next_arg (nmc, &argc, &argv, NULL);
- /* Register polkit agent */
nmc_start_polkit_agent_start_try (nmc);
nm_cli_spawn_pager (&nmc->nmc_config, &nmc->pager_data);
@@ -1542,38 +1536,33 @@ do_overview (NmCli *nmc, int argc, char **argv)
"\"nmcli connection show\" to get an overview on active connection profiles.\n"
"\n"
"Consult nmcli(1) and nmcli-examples(7) manual pages for complete usage details.\n"));
-
- return NMC_RESULT_SUCCESS;
}
-/*
- * Entry point function for 'nmcli monitor'
- */
-NMCResultCode
-do_monitor (NmCli *nmc, int argc, char **argv)
+void
+nmc_command_do_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv)
{
next_arg (nmc, &argc, &argv, NULL);
if (nmc->complete)
- return nmc->return_value;
+ return;
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;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: 'monitor' command '%s' is not valid."),
+ *argv);
}
-
usage_monitor ();
- return nmc->return_value;
+ return;
}
if (!nm_client_get_nm_running (nmc->client)) {
- char *str;
+ gs_free char *str = NULL;
str = nmc_colorize (&nmc->nmc_config, NM_META_COLOR_MANAGER_STOPPED,
_("Networkmanager is not running (waiting for it)\n"));
g_print ("%s", str);
- g_free (str);
}
g_signal_connect (nmc->client, "notify::" NM_CLIENT_NM_RUNNING,
@@ -1587,10 +1576,6 @@ do_monitor (NmCli *nmc, int argc, char **argv)
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;
}
diff --git a/clients/cli/general.h b/clients/cli/general.h
deleted file mode 100644
index dd63e43f72..0000000000
--- a/clients/cli/general.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2010 - 2014 Red Hat, Inc.
- */
-
-#ifndef NMC_GENERAL_H
-#define NMC_GENERAL_H
-
-#include "nmcli.h"
-
-NMCResultCode do_general (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_monitor (NmCli *nmc, int argc, char **argv);
-NMCResultCode do_overview (NmCli *nmc, int argc, char **argv);
-
-#endif /* NMC_GENERAL_H */
diff --git a/clients/cli/nmcli.c b/clients/cli/nmcli.c
index 08d3ab16e0..551c8d2987 100644
--- a/clients/cli/nmcli.c
+++ b/clients/cli/nmcli.c
@@ -19,14 +19,13 @@
#include <readline/history.h>
#include "nm-client-utils.h"
+#include "nm-glib-aux/nm-c-list.h"
#include "polkit-agent.h"
#include "utils.h"
#include "common.h"
#include "connections.h"
#include "devices.h"
-#include "general.h"
-#include "agent.h"
#include "settings.h"
#if defined(NM_DIST_VERSION)
@@ -75,7 +74,11 @@
static NmCli nm_cli = {
.client = NULL,
- .return_value = NMC_RESULT_SUCCESS,
+ .run_status = {
+ ._priv = {
+ .sources_lst_head = C_LIST_INIT (nm_cli.run_status._priv.sources_lst_head),
+ },
+ },
.timeout = -1,
@@ -83,7 +86,6 @@ static NmCli nm_cli = {
.pwds_hash = NULL,
.pk_listener = NULL,
- .should_wait = 0,
.nowait_flag = TRUE,
.nmc_config.print_output = NMC_PRINT_NORMAL,
.nmc_config.multiline_output = FALSE,
@@ -106,6 +108,76 @@ const NmCli *const nmc_meta_environment_arg = &nm_cli;
/*****************************************************************************/
+void
+nmc_run_status_return_message_full (NmcRunStatus *run_status,
+ NMCResultCode result_code,
+ char *result_message_take)
+{
+ nm_assert (run_status);
+ nm_assert (!run_status->_priv.is_returned);
+ nm_assert (run_status->_priv.result_code == 0);
+ nm_assert (!run_status->_priv.result_message);
+
+ g_cancellable_cancel (run_status->cancellable);
+
+ run_status->_priv.is_returned = TRUE;
+ run_status->_priv.result_code = result_code;
+ run_status->_priv.result_message = result_message_take;
+}
+
+void
+_nmc_run_status_signal_finished (NmcRunStatus *run_status)
+{
+ nm_assert (run_status);
+ nm_assert (!run_status->_priv.is_finished);
+
+ if (!run_status->_priv.is_returned)
+ nmc_run_status_return_success (run_status);
+
+ run_status->_priv.is_finished = TRUE;
+ nm_c_list_elem_free_all (&run_status->_priv.sources_lst_head,
+ (GDestroyNotify) nm_g_source_destroy_and_unref);
+}
+
+GSource *
+nmc_run_status_wait_add_timeout_full (NmcRunStatus *run_status,
+ guint timeout_msec,
+ GSourceFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy_notify)
+{
+ GSource *source;
+
+ nm_assert (run_status);
+ nm_assert (func);
+
+ source = nm_g_timeout_source_new (timeout_msec,
+ G_PRIORITY_DEFAULT,
+ func,
+ user_data,
+ destroy_notify);
+ g_source_attach (source, NULL);
+
+ c_list_link_tail (&run_status->_priv.sources_lst_head,
+ &nm_c_list_elem_new_stale (source)->lst);
+
+ return source;
+}
+
+void
+nmc_run_status_wait_remove_source (NmcRunStatus *run_status,
+ GSource *source_take)
+{
+ nm_auto_unref_gsource GSource *source = g_steal_pointer (&source_take);
+ NMCListElem *elem;
+
+ elem = nm_c_list_elem_find_first (&run_status->_priv.sources_lst_head, d, d == source);
+ if (elem)
+ nm_c_list_elem_free_full (elem, (GDestroyNotify) nm_g_source_destroy_and_unref);
+}
+
+/*****************************************************************************/
+
typedef struct {
NmCli *nmc;
int argc;
@@ -113,7 +185,6 @@ typedef struct {
} ArgsInfo;
/* --- Global variables --- */
-GMainLoop *loop = NULL;
struct termios termios_orig;
NM_CACHED_QUARK_FCN ("nmcli-error-quark", nmcli_error_quark)
@@ -258,26 +329,22 @@ usage (void)
"\n"));
}
-static const NMCCommand nmcli_cmds[] = {
- { "general", do_general, NULL, FALSE, FALSE },
- { "monitor", do_monitor, NULL, TRUE, FALSE },
- { "networking", do_networking, NULL, FALSE, FALSE },
- { "radio", do_radio, NULL, FALSE, FALSE },
- { "connection", do_connections, NULL, FALSE, FALSE },
- { "device", do_devices, NULL, FALSE, FALSE },
- { "agent", do_agent, NULL, FALSE, FALSE },
- { NULL, do_overview, usage, TRUE, TRUE },
-};
-
static gboolean
-matches_arg (NmCli *nmc, int *argc, char ***argv, const char *pattern, char **arg)
+matches_arg (NmCli *nmc,
+ int *argc,
+ const char *const**argv,
+ const char *pattern,
+ char **arg)
{
- char *opt = *argv[0];
+ gs_free char *opt_free = NULL;
+ const char *opt = (*argv)[0];
+ gs_free char *arg_tmp = NULL;
+ const char *s;
- if (nmc->return_value != NMC_RESULT_SUCCESS) {
- /* Don't process further matches if there has been an error. */
- return FALSE;
- }
+ nm_assert (!opt);
+ nm_assert (opt[0] == '-');
+ nm_assert (!arg || !*arg);
+ nm_assert (!nmc_run_status_is_returned (&nmc->run_status));
if (opt[1] == '-') {
/* We know one '-' was already seen by the caller.
@@ -288,33 +355,33 @@ matches_arg (NmCli *nmc, int *argc, char ***argv, const char *pattern, char **ar
if (arg) {
/* If there's a "=" separator, replace it with NUL so that matches()
* works and consider the part after it to be the arguemnt's value. */
- *arg = strchr (opt, '=');
- if (*arg) {
- **arg = '\0';
- (*arg)++;
+ s = strchr (opt, '=');
+ if (s) {
+ opt = nm_strndup_a (300, opt, s - opt, &opt_free);
+ arg_tmp = g_strdup (&s[1]);
}
}
- if (!matches (opt, pattern)) {
- if (arg && *arg) {
- /* Back off the replacement of "=". */
- (*arg)--;
- **arg = '=';
- }
+ if (!matches (opt, pattern))
return FALSE;
- }
- if (arg && !*arg) {
- /* We need a value, but the option didn't contain a "=<value>" part.
- * Proceed to the next argument. */
- (*argc)--;
- (*argv)++;
- if (!*argc) {
- g_string_printf (nmc->return_text, _("Error: missing argument for '%s' option."), opt);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ if (arg) {
+ if (arg_tmp)
+ *arg = g_steal_pointer (&arg_tmp);
+ else {
+ /* We need a value, but the option didn't contain a "=<value>" part.
+ * Proceed to the next argument. */
+ if (*argc <= 1) {
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: missing argument for '%s' option."),
+ opt);
+ return FALSE;
+ }
+ (*argc)--;
+ (*argv)++;
+ *arg = g_strdup (*argv[0]);
}
- *arg = *argv[0];
}
return TRUE;
@@ -699,32 +766,152 @@ set_colors (NmcColorOption color_option,
/*************************************************************************************/
+gboolean
+nmc_seen_sigint (NmcReadlineStatus *readline_status)
+{
+ return readline_status->seen_sigint;
+}
+
+void
+nmc_clear_sigint (NmcReadlineStatus *readline_status)
+{
+ readline_status->seen_sigint = FALSE;
+}
+
+static void
+nmc_set_sigint (NmcReadlineStatus *readline_status)
+{
+ readline_status->seen_sigint = TRUE;
+}
+
+void nmc_exit (void)
+{
+ tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig);
+ nmc_cleanup_readline ();
+ exit (1);
+}
+
+typedef struct {
+ int signo;
+ NmCli *nmc;
+} SignalHandlerData;
+
+static SignalHandlerData *
+signal_handler_data_new (NmCli *nmc, int signo)
+{
+ SignalHandlerData *d;
+
+ d = g_new (SignalHandlerData, 1);
+ *d = (SignalHandlerData) {
+ .nmc = nmc,
+ .signo = signo,
+ };
+ return d;
+}
+
static gboolean
-process_command_line (NmCli *nmc, int argc, char **argv)
+signal_handler (gpointer user_data)
{
+ SignalHandlerData *data = user_data;
+ NmCli *nmc = data->nmc;
+ int signo = data->signo;
+
+ switch (signo) {
+ case SIGINT:
+ if (nmc_get_in_readline (&nmc->readline_status)) {
+ nmc_set_sigint (&nmc->readline_status);
+ } else {
+ nmc_run_status_return (&nmc->run_status,
+ 0x80 + signo,
+ _("Error: nmcli terminated by signal %s (%d)"),
+ strsignal (signo),
+ signo);
+ }
+ break;
+ case SIGTERM:
+ nmc_run_status_return (&nmc->run_status,
+ 0x80 + signo,
+ _("Error: nmcli terminated by signal %s (%d)"),
+ strsignal (signo),
+ signo);
+ break;
+ }
+
+ return G_SOURCE_CONTINUE;
+}
+
+void
+nm_cli_spawn_pager (const NmcConfig *nmc_config,
+ NmcPagerData *pager_data)
+{
+ if (pager_data->pid != 0)
+ return;
+ pager_data->pid = nmc_terminal_spawn_pager (nmc_config);
+}
+
+int
+main (int argc_orig, char **argv_orig)
+{
+ static const NMCCommand nmcli_cmds[] = {
+ { "general", nmc_command_do_general, NULL, FALSE, FALSE },
+ { "monitor", nmc_command_do_monitor, NULL, TRUE, FALSE },
+ { "networking", nmc_command_do_networking, NULL, FALSE, FALSE },
+ { "radio", nmc_command_do_radio, NULL, FALSE, FALSE },
+ { "connection", nmc_command_do_connection, NULL, FALSE, FALSE },
+ { "device", nmc_command_do_device, NULL, FALSE, FALSE },
+ { "agent", nmc_command_do_agent, NULL, FALSE, FALSE },
+ { NULL, nmc_command_do_overview, usage, TRUE, TRUE },
+ };
NmcColorOption colors = NMC_USE_COLOR_AUTO;
- char *base;
+ gs_free const char **argv_clone1 = NULL;
+ const char *base;
+ pid_t ret;
+ NmCli *nmc = &nm_cli;
+ guint signal_id_term;
+ guint signal_id_int;
+ int argc = argc_orig;
+ const char *const*argv = (const char *const*) argv_orig;
+
+ /* Set locale to use environment variables */
+ setlocale (LC_ALL, "");
+
+#ifdef GETTEXT_PACKAGE
+ /* Set i18n stuff */
+ bindtextdomain (GETTEXT_PACKAGE, NMLOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+#endif
+
+ signal_id_term = g_unix_signal_add_full (G_PRIORITY_DEFAULT, SIGTERM, signal_handler, signal_handler_data_new (nmc, SIGTERM), g_free);
+ signal_id_int = g_unix_signal_add_full (G_PRIORITY_DEFAULT, SIGINT, signal_handler, signal_handler_data_new (nmc, SIGINT), g_free);
+
+ /* Save terminal settings */
+ tcgetattr (STDIN_FILENO, &termios_orig);
base = strrchr (argv[0], '/');
- if (base == NULL)
+ if (!base)
base = argv[0];
else
base++;
- if (argc > 1 && nm_streq (argv[1], "--complete-args")) {
- nmc->complete = TRUE;
- argv[1] = argv[0];
- next_arg (nmc, &argc, &argv, NULL);
+
+ arg_move_next (&argc, &argv);
+
+ if ( argc >= 1
+ && nm_streq (argv[0], "--complete-args")) {
+ nmc->complete_mutable = TRUE;
+ arg_move_next (&argc, &argv);
}
- next_arg (nmc, &argc, &argv, NULL);
- /* parse options */
- while (argc) {
- char *value;
+ nmc->run_status.cancellable_mutable = g_cancellable_new ();
+
+ while (argc > 0) {
+ gs_free char *value = NULL;
if (argv[0][0] != '-')
break;
- if (argc == 1 && nmc->complete) {
+ if ( argc == 1
+ && nmc->complete) {
nmc_complete_strings (argv[0], "--terse", "--pretty", "--mode", "--overview",
"--colors", "--escape",
"--fields", "--nocheck", "--get-values",
@@ -741,27 +928,31 @@ process_command_line (NmCli *nmc, int argc, char **argv)
nmc->nmc_config_mutable.overview = TRUE;
} else if (matches_arg (nmc, &argc, &argv, "-terse", NULL)) {
if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) {
- g_string_printf (nmc->return_text, _("Error: Option '--terse' is specified the second time."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: Option '--terse' is specified the second time."));
+ break;
}
else if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) {
- g_string_printf (nmc->return_text, _("Error: Option '--terse' is mutually exclusive with '--pretty'."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: Option '--terse' is mutually exclusive with '--pretty'."));
+ break;
}
else
nmc->nmc_config_mutable.print_output = NMC_PRINT_TERSE;
} else if (matches_arg (nmc, &argc, &argv, "-pretty", NULL)) {
if (nmc->nmc_config.print_output == NMC_PRINT_PRETTY) {
- g_string_printf (nmc->return_text, _("Error: Option '--pretty' is specified the second time."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: Option '--pretty' is specified the second time."));
+ break;
}
else if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) {
- g_string_printf (nmc->return_text, _("Error: Option '--pretty' is mutually exclusive with '--terse'."));
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: Option '--pretty' is mutually exclusive with '--terse'."));
+ break;
}
else
nmc->nmc_config_mutable.print_output = NMC_PRINT_PRETTY;
@@ -774,9 +965,10 @@ process_command_line (NmCli *nmc, int argc, char **argv)
else if (matches (value, "multiline"))
nmc->nmc_config_mutable.multiline_output = TRUE;
else {
- g_string_printf (nmc->return_text, _("Error: '%s' is not a valid argument for '%s' option."), value, argv[0]);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '%s' is not a valid argument for '%s' option."), value, argv[0]);
+ break;
}
} else if (matches_arg (nmc, &argc, &argv, "-colors", &value)) {
if (argc == 1 && nmc->complete)
@@ -788,9 +980,10 @@ process_command_line (NmCli *nmc, int argc, char **argv)
else if (matches (value, "no"))
colors = NMC_USE_COLOR_NO;
else {
- g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), value, argv[0]);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '%s' is not valid argument for '%s' option."), value, argv[0]);
+ break;
}
} else if (matches_arg (nmc, &argc, &argv, "-escape", &value)) {
if (argc == 1 && nmc->complete)
@@ -800,9 +993,10 @@ process_command_line (NmCli *nmc, int argc, char **argv)
else if (matches (value, "no"))
nmc->nmc_config_mutable.escape_values = FALSE;
else {
- g_string_printf (nmc->return_text, _("Error: '%s' is not valid argument for '%s' option."), value, argv[0]);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '%s' is not valid argument for '%s' option."), value, argv[0]);
+ break;
}
} else if (matches_arg (nmc, &argc, &argv, "-fields", &value)) {
if (argc == 1 && nmc->complete)
@@ -824,106 +1018,66 @@ process_command_line (NmCli *nmc, int argc, char **argv)
unsigned long timeout;
if (!nmc_string_to_uint (value, TRUE, 0, G_MAXINT, &timeout)) {
- g_string_printf (nmc->return_text, _("Error: '%s' is not a valid timeout."), value);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: '%s' is not a valid timeout."), value);
+ break;
}
nmc->timeout = (int) timeout;
} else if (matches_arg (nmc, &argc, &argv, "-version", NULL)) {
if (!nmc->complete)
g_print (_("nmcli tool, version %s\n"), NMCLI_VERSION);
- return NMC_RESULT_SUCCESS;
+ nmc_run_status_return_success (&nmc->run_status);
+ break;
} else if (matches_arg (nmc, &argc, &argv, "-help", NULL)) {
if (!nmc->complete)
usage ();
- return NMC_RESULT_SUCCESS;
+ nmc_run_status_return_success (&nmc->run_status);
+ break;
} else {
- if (nmc->return_value == NMC_RESULT_SUCCESS) {
- g_string_printf (nmc->return_text, _("Error: Option '%s' is unknown, try 'nmcli -help'."), argv[0]);
- nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
- }
- return FALSE;
+ nmc_run_status_return (&nmc->run_status,
+ NMC_RESULT_ERROR_USER_INPUT,
+ _("Error: Option '%s' is unknown, try 'nmcli -help'."), argv[0]);
+ break;
}
next_arg (nmc, &argc, &argv, NULL);
}
- /* Ignore --overview when fields are set explicitly */
- if (nmc->required_fields)
- nmc->nmc_config_mutable.overview = FALSE;
+ if (!nmc_run_status_is_returned (&nmc->run_status)) {
+ /* Ignore --overview when fields are set explicitly */
+ if (nmc->required_fields)
+ nmc->nmc_config_mutable.overview = FALSE;
- set_colors (colors,
- &nmc->nmc_config_mutable.use_colors,
- &nmc->palette_buffer,
- nmc->nmc_config_mutable.palette);
+ set_colors (colors,
+ &nmc->nmc_config_mutable.use_colors,
+ &nmc->palette_buffer,
+ nmc->nmc_config_mutable.palette);
- /* Now run the requested command */
- nmc_do_cmd (nmc, nmcli_cmds, *argv, argc, argv);
-
- return TRUE;
-}
-
-static gboolean nmcli_sigint = FALSE;
-
-gboolean
-nmc_seen_sigint (void)
-{
- return nmcli_sigint;
-}
-
-void
-nmc_clear_sigint (void)
-{
- nmcli_sigint = FALSE;
-}
-
-void nmc_exit (void)
-{
- tcsetattr (STDIN_FILENO, TCSADRAIN, &termios_orig);
- nmc_cleanup_readline ();
- exit (1);
-}
-
-static gboolean
-signal_handler (gpointer user_data)
-{
- int signo = GPOINTER_TO_INT (user_data);
+ /* Now run the requested command */
+ nmc_do_cmd (nmc, nmcli_cmds, *argv, argc, argv);
+ }
- switch (signo) {
- case SIGINT:
- if (nmc_get_in_readline ()) {
- nmcli_sigint = TRUE;
- } else {
- nm_cli.return_value = 0x80 + signo;
- g_string_printf (nm_cli.return_text, _("Error: nmcli terminated by signal %s (%d)"),
- strsignal (signo), signo);
- g_main_loop_quit (loop);
+ while (TRUE) {
+ if (nmc_run_status_wait_is_finished (&nmc->run_status)) {
+ nmc_run_status_return_success_if_necessary (&nmc->run_status);
+ break;
}
- break;
- case SIGTERM:
- nm_cli.return_value = 0x80 + signo;
- g_string_printf (nm_cli.return_text, _("Error: nmcli terminated by signal %s (%d)"),
- strsignal (signo), signo);
- nmc_exit ();
- break;
+ g_main_context_iteration (NULL, TRUE);
}
- return G_SOURCE_CONTINUE;
-}
+ nm_clear_g_source (&
-void
-nm_cli_spawn_pager (const NmcConfig *nmc_config,
- NmcPagerData *pager_data)
-{
- if (pager_data->pid != 0)
- return;
- pager_data->pid = nmc_terminal_spawn_pager (nmc_config);
-}
+ if (nm_cli.complete) {
+ /* Remove error statuses from command completion runs. */
+ if (nm_cli.return_value < NMC_RESULT_COMPLETE_FILE)
+ nm_cli.return_value = NMC_RESULT_SUCCESS;
+ } else if (nm_cli.return_value != NMC_RESULT_SUCCESS) {
+ /* Print result descripting text */
+ g_printerr ("%s\n", nm_cli.return_text->str);
+ }
-static void
-nmc_cleanup (NmCli *nmc)
-{
- pid_t ret;
+ g_main_loop_unref (loop);
g_clear_object (&nmc->client);
@@ -952,44 +1106,8 @@ nmc_cleanup (NmCli *nmc)
nm_clear_g_free (&nmc->palette_buffer);
nmc_polkit_agent_fini (nmc);
-}
-int
-main (int argc, char *argv[])
-{
- /* Set locale to use environment variables */
- setlocale (LC_ALL, "");
-
-#ifdef GETTEXT_PACKAGE
- /* Set i18n stuff */
- bindtextdomain (GETTEXT_PACKAGE, NMLOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- textdomain (GETTEXT_PACKAGE);
-#endif
-
- /* Save terminal settings */
- tcgetattr (STDIN_FILENO, &termios_orig);
-
- nm_cli.return_text = g_string_new (_("Success"));
- loop = g_main_loop_new (NULL, FALSE);
-
- g_unix_signal_add (SIGTERM, signal_handler, GINT_TO_POINTER (SIGTERM));
- g_unix_signal_add (SIGINT, signal_handler, GINT_TO_POINTER (SIGINT));
-
- if (process_command_line (&nm_cli, argc, argv))
- g_main_loop_run (loop);
-
- if (nm_cli.complete) {
- /* Remove error statuses from command completion runs. */
- if (nm_cli.return_value < NMC_RESULT_COMPLETE_FILE)
- nm_cli.return_value = NMC_RESULT_SUCCESS;
- } else if (nm_cli.return_value != NMC_RESULT_SUCCESS) {
- /* Print result descripting text */
- g_printerr ("%s\n", nm_cli.return_text->str);
- }
-
- g_main_loop_unref (loop);
- nmc_cleanup (&nm_cli);
+ g_clear_object (&nmc->run_status.cancellable_mutable);
- return nm_cli.return_value;
+ return nmc->run_status.result_code;
}
diff --git a/clients/cli/nmcli.h b/clients/cli/nmcli.h
index 96a1be1dde..2c185da2b0 100644
--- a/clients/cli/nmcli.h
+++ b/clients/cli/nmcli.h
@@ -8,6 +8,7 @@
#include "nm-secret-agent-simple.h"
#include "nm-meta-setting-desc.h"
+#include "c-list/src/c-list.h"
struct _NMPolkitListener;
@@ -47,9 +48,6 @@ typedef enum {
/* Connection/Device/AP not found */
NMC_RESULT_ERROR_NOT_FOUND = 10,
-
- /* --complete-args signals a file name may follow */
- NMC_RESULT_COMPLETE_FILE = 65,
} NMCResultCode;
typedef enum {
@@ -105,6 +103,27 @@ typedef struct {
pid_t pid;
} NmcPagerData;
+typedef struct {
+ union {
+ GCancellable *const cancellable;
+ GCancellable *cancellable_mutable;
+ };
+ struct {
+ CList sources_lst_head;
+ char *result_message;
+ int should_wait;
+ NMCResultCode result_code;
+ bool is_finished:1;
+ bool is_returned:1;
+ bool complete_file:1;
+ } _priv;
+} NmcRunStatus;
+
+typedef struct {
+ bool in_readline;
+ bool seen_sigint;
+} NmcReadlineStatus;
+
typedef struct _NmcOutputData {
GPtrArray *output_data; /* GPtrArray of arrays of NmcOutputField structs - accumulates data for output */
} NmcOutputData;
@@ -113,9 +132,8 @@ typedef struct _NmcOutputData {
typedef struct _NmCli {
NMClient *client; /* Pointer to NMClient of libnm */
- NMCResultCode return_value; /* Return code of nmcli */
- GString *return_text; /* Reason text */
-
+ NmcRunStatus run_status;
+ NmcReadlineStatus readline_status;
NmcPagerData pager_data;
int timeout; /* Operation timeout */
@@ -124,7 +142,6 @@ typedef struct _NmCli {
GHashTable *pwds_hash; /* Hash table with passwords in passwd-file */
struct _NMPolkitListener *pk_listener; /* polkit agent listener */
- int should_wait; /* Semaphore indicating whether nmcli should not end or not yet */
gboolean nowait_flag; /* '--nowait' option; used for passing to callbacks */
gboolean mode_specified; /* Whether tabular/multiline mode was specified via '--mode' option */
union {
@@ -133,7 +150,12 @@ typedef struct _NmCli {
};
char *required_fields; /* Required fields in output: '--fields' option */
gboolean ask; /* Ask for missing parameters: option '--ask' */
- gboolean complete; /* Autocomplete the command line */
+
+ union {
+ const bool complete;
+ bool complete_mutable;
+ };
+
gboolean editor_status_line; /* Whether to display status line in connection editor */
gboolean editor_save_confirmation; /* Whether to ask for confirmation on saving connections with 'autoconnect=yes' */
@@ -148,8 +170,8 @@ GQuark nmcli_error_quark (void);
extern GMainLoop *loop;
-gboolean nmc_seen_sigint (void);
-void nmc_clear_sigint (void);
+gboolean nmc_seen_sigint (NmcReadlineStatus *readline_status);
+void nmc_clear_sigint (NmcReadlineStatus *readline_status);
void nmc_set_sigquit_internal (void);
void nmc_exit (void);
@@ -164,4 +186,157 @@ void nmc_empty_output_fields (NmcOutputData *output_data);
.output_data = g_ptr_array_new_full (20, g_free), \
}
+/*****************************************************************************/
+
+void _nmc_run_status_signal_finished (NmcRunStatus *run_status);
+
+static inline void
+nmc_run_status_wait_push (NmcRunStatus *run_status)
+{
+ nm_assert (run_status);
+ nm_assert (run_status->_priv.should_wait < G_MAXINT);
+ nm_assert (!run_status->_priv.is_finished);
+
+ run_status->_priv.should_wait++;
+}
+
+static inline void
+nmc_run_status_wait_pop (NmcRunStatus *run_status)
+{
+ nm_assert (run_status);
+ nm_assert (run_status->_priv.should_wait > 0);
+ nm_assert (!run_status->_priv.is_finished);
+
+ if (--run_status->_priv.should_wait == 0)
+ _nmc_run_status_signal_finished (run_status);
+}
+
+static inline void
+_nm_auto_pop_run_status (NmCli **p_cli)
+{
+ if (*p_cli)
+ nmc_run_status_wait_pop (&((*p_cli)->run_status));
+}
+
+#define nm_auto_pop_run_status nm_auto (_nm_auto_pop_run_status)
+
+static inline gboolean
+nmc_run_status_wait_is_finished (NmcRunStatus *run_status)
+{
+ nm_assert (run_status);
+ nm_assert (run_status->_priv.should_wait >= 0);
+ nm_assert (!run_status->_priv.is_finished);
+
+ if (run_status->_priv.should_wait > 0)
+ return FALSE;
+ _nmc_run_status_signal_finished (run_status);
+ return TRUE;
+}
+
+GSource *nmc_run_status_wait_add_timeout_full (NmcRunStatus *run_status,
+ guint timeout_msec,
+ GSourceFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy_notify);
+static inline GSource *
+nmc_run_status_wait_add_timeout (NmcRunStatus *run_status,
+ guint timeout_msec,
+ GSourceFunc func,
+ gpointer user_data)
+{
+ return nmc_run_status_wait_add_timeout_full (run_status, timeout_msec, func, user_data, NULL);
+}
+
+void nmc_run_status_wait_remove_source (NmcRunStatus *run_status,
+ GSource *source_take);
+
+static inline gboolean
+nmc_run_status_is_returned (NmcRunStatus *run_status)
+{
+ return run_status->_priv.is_returned;
+}
+
+void nmc_run_status_return_message_full (NmcRunStatus *run_status,
+ NMCResultCode result_code,
+ char *result_message_take);
+
+static inline void
+nmc_run_status_return_message (NmcRunStatus *run_status,
+ NMCResultCode result_code,
+ const char *result_message)
+{
+ nmc_run_status_return_message_full (run_status, result_code, g_strdup (result_message));
+}
+
+#define nmc_run_status_return(run_status, result_code, ...) \
+ G_STMT_START { \
+ NmcRunStatus *_run_status = (run_status); \
+ NMCResultCode _result_code = (result_code); \
+ \
+ if (NM_NARG (__VA_ARGS__) == 1) \
+ nmc_run_status_return_message (_run_status, _result_code, _NM_UTILS_MACRO_FIRST (__VA_ARGS__)); \
+ else { \
+ gs_free char *_msg = g_strdup_printf (__VA_ARGS__); \
+ \
+ nmc_run_status_return_message (_run_status, _result_code, _msg); \
+ } \
+ } G_STMT_END
+
+static inline void
+nmc_run_status_return_success (NmcRunStatus *run_status)
+{
+ nmc_run_status_return_message (run_status, NMC_RESULT_SUCCESS, NULL);
+}
+
+static inline void
+nmc_run_status_return_success_if_necessary (NmcRunStatus *run_status)
+{
+ /* By default, if the result was not set upon completion we anyway assume
+ * success. So, this has only the purpose to mark the result as set so
+ * that we assert that we won't try to set the result again. This is
+ * only to catch bugs where we try to set the result multiple times. */
+ nm_assert (run_status);
+ if (!run_status->_priv.is_returned)
+ nmc_run_status_return_success (run_status);
+}
+
+void nmc_run_status_return_append_message (NmcRunStatus *run_status,
+ const char *fmt,
+ ...) G_GNUC_PRINTF (2, 3);
+
+static inline void
+nmc_run_status_set_complete_file (NmcRunStatus *run_status)
+{
+ nm_assert (run_status);
+ nm_assert (!run_status->_priv.is_returned);
+
+ run_status->_priv.complete_file = TRUE;
+}
+
+/*****************************************************************************/
+
+struct _NMCCommand;
+
+typedef struct _NMCCommand {
+ const char *cmd;
+ void (*func) (const struct _NMCCommand *cmd,
+ NmCli *nmc,
+ int argc,
+ const char *const*argv);
+ void (*usage) (void);
+ bool needs_client;
+ bool needs_nm_running;
+} NMCCommand;
+
+void nmc_command_do_agent (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_do_general (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_do_networking (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_do_radio (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_do_monitor (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_do_overview (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_do_connection (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+void nmc_command_do_device (const NMCCommand *cmd, NmCli *nmc, int argc, const char *const*argv);
+
+/*****************************************************************************/
+
#endif /* NMC_NMCLI_H */
diff --git a/clients/cli/utils.c b/clients/cli/utils.c
index 67d5a742a0..61aa0a629a 100644
--- a/clients/cli/utils.c
+++ b/clients/cli/utils.c
@@ -154,7 +154,7 @@ parse_global_arg (NmCli *nmc, const char *arg)
* -1 otherwise (no more args).
*/
int
-next_arg (NmCli *nmc, int *argc, char ***argv, ...)
+next_arg (NmCli *nmc, int *argc, const char *const**argv, ...)
{
va_list args;
const char *cmd_option;
@@ -164,20 +164,20 @@ next_arg (NmCli *nmc, int *argc, char ***argv, ...)
do {
int cmd_option_pos = 1;
- if (*argc > 0) {
- (*argc)--;
- (*argv)++;
- }
+ if (*argc > 0)
+ arg_move_next (argc, argv);
if (*argc == 0)
return -1;
va_start (args, argv);
- if (nmc && nmc->complete && *argc == 1) {
+ if ( nmc
+ && nmc->complete
+ && *argc == 1) {
while ((cmd_option = va_arg (args, const char *)))
nmc_complete_strings (**argv, cmd_option);
- if (***argv == '-')
+ if ((**argv)[0] == '-')
nmc_complete_strings (**argv, "--ask", "--show-secrets");
va_end (args);
@@ -248,7 +248,11 @@ nmc_arg_is_option (const char *str, const char *opt_name)
* Returns: TRUE on success, FALSE on an error and sets 'error'
*/
gboolean
-nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GError **error)
+nmc_parse_args (nmc_arg_t *arg_arr,
+ gboolean last,
+ int *argc,
+ const char *const**argv,
+ GError **error)
{
nmc_arg_t *p;
gboolean found;
@@ -483,8 +487,11 @@ nmc_get_user_input (const char *ask_str)
* Split string in 'line' according to 'delim' to (argument) array.
*/
int
-nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquote,
- char ***argv, int *argc)
+nmc_string_to_arg_array (const char *line,
+ const char *delim,
+ gboolean unquote,
+ char ***argv,
+ int *argc)
{
gs_free const char **arr0 = NULL;
char **arr;
diff --git a/clients/cli/utils.h b/clients/cli/utils.h
index 87e93ce082..1cdde93c8e 100644
--- a/clients/cli/utils.h
+++ b/clients/cli/utils.h
@@ -8,8 +8,6 @@
#include "nmcli.h"
-/* === Types === */
-
typedef struct {
const char *name;
gboolean has_value;
@@ -18,11 +16,26 @@ typedef struct {
gboolean found;
} nmc_arg_t;
-/* === Functions === */
-int next_arg (NmCli *nmc, int *argc, char ***argv, ...);
+static inline void
+arg_move_next (int *argc, const char *const**argv)
+{
+ nm_assert (argc);
+ nm_assert (argv);
+ nm_assert (*argc > 0);
+ nm_assert ((gsize) *argc == NM_PTRARRAY_LEN (argv));
+
+ argc--;
+ argv++;
+}
+
+int next_arg (NmCli *nmc, int *argc, const char *const**argv, ...) G_GNUC_NULL_TERMINATED;
gboolean nmc_arg_is_help (const char *arg);
gboolean nmc_arg_is_option (const char *arg, const char *opt_name);
-gboolean nmc_parse_args (nmc_arg_t *arg_arr, gboolean last, int *argc, char ***argv, GError **error);
+gboolean nmc_parse_args (nmc_arg_t *arg_arr,
+ gboolean last,
+ int *argc,
+ const char *const**argv,
+ GError **error);
char *ssid_to_hex (const char *str, gsize len);
void nmc_terminal_erase_line (void);
void nmc_terminal_show_progress (const char *str);
@@ -31,8 +44,11 @@ char *nmc_colorize (const NmcConfig *nmc_config, NMMetaColor color, const char *
void nmc_filter_out_colors_inplace (char *str);
char *nmc_filter_out_colors (const char *str);
char *nmc_get_user_input (const char *ask_str);
-int nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquote,
- char ***argv, int *argc);
+int nmc_string_to_arg_array (const char *line,
+ const char *delim,
+ gboolean unquote,
+ char ***argv,
+ int *argc);
const char *nmc_string_is_valid (const char *input, const char **allowed, GError **error);
char * nmc_util_strv_for_display (const char *const*strv, gboolean brackets);
int nmc_string_screen_width (const char *start, const char *end);