cli: use nm_client_add_connection2() API from nmcli

Make use of the new API. Note that AddConnection2() covers all
functionality of AddConnection() and AddConnectionUnsaved(). Let's
only use one API for all.

There is a minor downside to this patch: now nmcli requires
libnm 1.20 API. Note that libnm's nm_client_add_connection2()
makes an effort to avoid AddConnection2() under the hood to
still work against older server versions. So, you can use nmcli
with libnm 1.20 to talk to older versions of NetworkManager.

But with this change nmcli strictly requires libnm 1.20. I think that is
sensible because commonly nmcli requires a libnm version that is as new
as itself.
Also, the value of allowing nmcli to talk to older NetworkManager
versions is during package upgrade (where the daemon might not be
restarted). This is much less concern w.r.t. to updating the nmcli/libnm
combo, which is commonly packaged together.
This commit is contained in:
Thomas Haller 2019-07-10 16:43:52 +02:00
parent 22c8721f35
commit 64c178712a

View file

@ -41,6 +41,8 @@
#include "devices.h"
#include "polkit-agent.h"
/*****************************************************************************/
typedef enum {
PROPERTY_INF_FLAG_NONE = 0x0,
PROPERTY_INF_FLAG_DISABLED = 0x1, /* Don't ask due to runtime decision. */
@ -50,14 +52,13 @@ typedef enum {
typedef char *(*CompEntryFunc) (const char *, int);
typedef struct _OptionInfo OptionInfo;
struct _OptionInfo {
typedef struct _OptionInfo {
const NMMetaSettingInfoEditor *setting_info;
const char *property;
const char *option;
gboolean (*check_and_set)(NmCli *nmc, NMConnection *connection, const OptionInfo *option, const char *value, GError **error);
gboolean (*check_and_set)(NmCli *nmc, NMConnection *connection, const struct _OptionInfo *option, const char *value, GError **error);
CompEntryFunc generator_func;
};
} OptionInfo;
/* define some prompts for connection editor */
#define EDITOR_PROMPT_SETTING _("Setting name? ")
@ -96,6 +97,47 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (vpn_connection_state_to_string, NMVpnConnecti
NM_UTILS_LOOKUP_ITEM_IGNORE (NM_VPN_CONNECTION_STATE_UNKNOWN),
)
/*****************************************************************************/
typedef struct {
NmCli *nmc;
char *orig_id;
char *orig_uuid;
char *new_id;
} AddConnectionInfo;
static AddConnectionInfo *
_add_connection_info_new (NmCli *nmc,
NMConnection *orig_connection,
NMConnection *new_connection)
{
AddConnectionInfo *info;
info = g_slice_new (AddConnectionInfo);
*info = (AddConnectionInfo) {
.nmc = nmc,
.orig_id = orig_connection ? g_strdup (nm_connection_get_id (orig_connection)) : NULL,
.orig_uuid = orig_connection ? g_strdup (nm_connection_get_uuid (orig_connection)) : NULL,
.new_id = g_strdup (nm_connection_get_id (new_connection)),
};
return info;
}
static void
_add_connection_info_free (AddConnectionInfo *info)
{
g_free (info->orig_id);
g_free (info->orig_uuid);
g_free (info->new_id);
nm_g_slice_free (info);
}
NM_AUTO_DEFINE_FCN (AddConnectionInfo *, _nm_auto_free_add_connection_info, _add_connection_info_free)
#define nm_auto_free_add_connection_info nm_auto (_nm_auto_free_add_connection_info)
/*****************************************************************************/
/* Essentially a version of nm_setting_connection_get_connection_type() that
* prefers an alias instead of the settings name when in pretty print mode.
* That is so that we print "wifi" instead of "802-11-wireless" in "nmcli c". */
@ -4755,28 +4797,23 @@ nmc_read_connection_properties (NmCli *nmc,
return TRUE;
}
typedef struct {
NmCli *nmc;
char *con_name;
} AddConnectionInfo;
static void
add_connection_cb (GObject *client,
GAsyncResult *result,
gpointer user_data)
{
AddConnectionInfo *info = (AddConnectionInfo *) user_data;
nm_auto_free_add_connection_info AddConnectionInfo *info = user_data;
NmCli *nmc = info->nmc;
NMRemoteConnection *connection;
GError *error = NULL;
const GPtrArray *connections;
guint i, found;
connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
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->con_name, error->message);
info->new_id, error->message);
g_error_free (error);
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
} else {
@ -4788,7 +4825,7 @@ add_connection_cb (GObject *client,
if ((NMConnection *) connection == candidate)
continue;
if (nm_streq0 (nm_connection_get_id (candidate), info->con_name))
if (nm_streq0 (nm_connection_get_id (candidate), info->new_id))
found++;
}
if (found > 0) {
@ -4796,7 +4833,7 @@ add_connection_cb (GObject *client,
"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->con_name,
info->new_id,
nm_connection_get_uuid (NM_CONNECTION (connection)),
found);
}
@ -4808,30 +4845,39 @@ add_connection_cb (GObject *client,
g_object_unref (connection);
}
g_free (info->con_name);
g_free (info);
quit ();
}
static void
add_new_connection (gboolean persistent,
NMClient *client,
NMConnection *connection,
GAsyncReadyCallback callback,
gpointer user_data)
add_connection (NMClient *client,
NMConnection *connection,
gboolean temporary,
GAsyncReadyCallback callback,
gpointer user_data)
{
nm_client_add_connection_async (client, connection, persistent,
NULL, callback, user_data);
nm_client_add_connection2 (client,
nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL),
temporary
? NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY
: NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK,
NULL,
TRUE,
NULL,
callback,
user_data);
}
static void
update_connection (gboolean persistent,
NMRemoteConnection *connection,
update_connection (NMRemoteConnection *connection,
gboolean temporary,
GAsyncReadyCallback callback,
gpointer user_data)
{
nm_remote_connection_commit_changes_async (connection, persistent,
NULL, callback, user_data);
nm_remote_connection_commit_changes_async (connection,
!temporary,
NULL,
callback,
user_data);
}
static gboolean
@ -5150,7 +5196,6 @@ do_connection_add (NmCli *nmc, int argc, char **argv)
gs_unref_object NMConnection *connection = NULL;
NMSettingConnection *s_con;
gs_free_error GError *error = NULL;
AddConnectionInfo *info = NULL;
gboolean save_bool = TRUE;
gboolean seen_dash_dash = FALSE;
NMMetaSettingType s;
@ -5295,19 +5340,13 @@ read_properties:
}
}
add_connection (nmc->client,
connection,
!save_bool,
add_connection_cb,
_add_connection_info_new (nmc, NULL, connection));
nmc->should_wait++;
info = g_malloc0 (sizeof (AddConnectionInfo));
info->nmc = nmc;
info->con_name = g_strdup (nm_connection_get_id (connection));
/* Tell the settings service to add the new connection */
add_new_connection (save_bool,
nmc->client,
connection,
add_connection_cb,
info);
finish:
reset_options ();
return nmc->return_value;
@ -6656,14 +6695,11 @@ add_connection_editor_cb (GObject *client,
GAsyncResult *result,
gpointer user_data)
{
NMRemoteConnection *connection;
GError *error = NULL;
gs_unref_object NMRemoteConnection *connection = NULL;
gs_free_error GError *error = NULL;
connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
connection = nm_client_add_connection2_finish (NM_CLIENT (client), result, NULL, &error);
set_info_and_signal_editor_thread (error, NULL);
g_clear_object (&connection);
g_clear_error (&error);
}
static void
@ -7242,7 +7278,6 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
const NMMetaSettingValidPartItem *const*valid_settings_slave;
gs_free char *valid_settings_str = NULL;
const char *s_type = NULL;
AddConnectionInfo *info = NULL;
gboolean temp_changes;
GError *err1 = NULL;
NmcEditorMenuContext menu_ctx = { 0 };
@ -7761,7 +7796,7 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
case NMC_EDITOR_MAIN_CMD_SAVE:
/* Save the connection */
if (nm_connection_verify (connection, &err1)) {
gboolean persistent = TRUE;
gboolean temporary = FALSE;
gboolean connection_changed;
nm_auto_unref_gsource GSource *source = NULL;
gboolean timeout = FALSE;
@ -7770,9 +7805,9 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
/* parse argument */
if (cmd_arg) {
if (matches (cmd_arg, "temporary"))
persistent = FALSE;
temporary = TRUE;
else if (matches (cmd_arg, "persistent"))
persistent = TRUE;
temporary = FALSE;
else {
g_print (_("Error: invalid argument '%s'\n"), cmd_arg);
break;
@ -7788,21 +7823,17 @@ editor_menu_main (NmCli *nmc, NMConnection *connection, const char *connection_t
}
if (!rem_con) {
/* Tell the settings service to add the new connection */
info = g_malloc0 (sizeof (AddConnectionInfo));
info->nmc = nmc;
info->con_name = g_strdup (nm_connection_get_id (connection));
add_new_connection (persistent,
nmc->client,
connection,
add_connection_editor_cb,
info);
add_connection (nmc->client,
connection,
temporary,
add_connection_editor_cb,
NULL);
connection_changed = TRUE;
} else {
/* Save/update already saved (existing) connection */
nm_connection_replace_settings_from_connection (NM_CONNECTION (rem_con),
connection);
update_connection (persistent, rem_con, update_connection_editor_cb, NULL);
update_connection (rem_con, temporary, update_connection_editor_cb, NULL);
handler_id = g_signal_connect (rem_con,
NM_CONNECTION_CHANGED,
@ -8403,35 +8434,27 @@ do_connection_modify (NmCli *nmc,
if (nmc->complete)
return nmc->return_value;
update_connection (!temporary, rc, modify_connection_cb, nmc);
update_connection (rc, temporary, modify_connection_cb, nmc);
nmc->should_wait++;
return nmc->return_value;
}
typedef struct {
NmCli *nmc;
char *orig_id;
char *orig_uuid;
char *con_id;
} CloneConnectionInfo;
static void
clone_connection_cb (GObject *client,
GAsyncResult *result,
gpointer user_data)
{
CloneConnectionInfo *info = (CloneConnectionInfo *) user_data;
nm_auto_free_add_connection_info AddConnectionInfo *info = user_data;
NmCli *nmc = info->nmc;
NMRemoteConnection *connection;
GError *error = NULL;
gs_unref_object NMRemoteConnection *connection = NULL;
gs_free_error GError *error = NULL;
connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
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->con_id, error->message);
g_error_free (error);
info->new_id, error->message);
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
} else {
g_print (_("%s (%s) cloned as %s (%s).\n"),
@ -8439,13 +8462,8 @@ clone_connection_cb (GObject *client,
info->orig_uuid,
nm_connection_get_id (NM_CONNECTION (connection)),
nm_connection_get_uuid (NM_CONNECTION (connection)));
g_object_unref (connection);
}
g_free (info->con_id);
g_free (info->orig_id);
g_free (info->orig_uuid);
g_slice_free (CloneConnectionInfo, info);
quit ();
}
@ -8454,11 +8472,9 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
{
NMConnection *connection = NULL;
gs_unref_object NMConnection *new_connection = NULL;
NMSettingConnection *s_con;
CloneConnectionInfo *info;
const char *new_name;
gs_free char *new_name_ask = NULL;
char *uuid;
gs_free char *new_name_free = NULL;
gs_free char *uuid = NULL;
gboolean temporary = FALSE;
char **arg_arr = NULL;
int arg_num;
@ -8499,8 +8515,8 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
if (argv[0])
new_name = *argv;
else if (nmc->ask) {
new_name = new_name_ask = nmc_readline (&nmc->nmc_config,
_("New connection name: "));
new_name = new_name_free = nmc_readline (&nmc->nmc_config,
_("New connection name: "));
} else {
g_string_printf (nmc->return_text, _("Error: <new name> argument is missing."));
NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
@ -8511,35 +8527,23 @@ do_connection_clone (NmCli *nmc, int argc, char **argv)
NMC_RETURN (nmc, NMC_RESULT_ERROR_USER_INPUT);
}
/* Copy the connection */
new_connection = nm_simple_connection_new_clone (connection);
s_con = nm_connection_get_setting_connection (new_connection);
g_assert (s_con);
uuid = nm_utils_uuid_generate ();
g_object_set (s_con,
g_object_set (nm_connection_get_setting_connection (new_connection),
NM_SETTING_CONNECTION_ID, new_name,
NM_SETTING_CONNECTION_UUID, uuid,
NULL);
g_free (uuid);
/* Merge secrets into the new connection */
update_secrets_in_connection (NM_REMOTE_CONNECTION (connection), new_connection);
info = g_slice_new0 (CloneConnectionInfo);
info->nmc = nmc;
info->orig_id = g_strdup (nm_connection_get_id (connection));
info->orig_uuid = g_strdup (nm_connection_get_uuid (connection));
info->con_id = g_strdup (nm_connection_get_id (new_connection));
/* Add the new cloned connection to NetworkManager */
add_new_connection (!temporary,
nmc->client,
new_connection,
clone_connection_cb,
info);
add_connection (nmc->client,
new_connection,
temporary,
clone_connection_cb,
_add_connection_info_new (nmc, connection, new_connection));
nmc->should_wait++;
return nmc->return_value;
}
@ -8826,7 +8830,6 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
const char *type = NULL, *filename = NULL;
gs_free char *type_ask = NULL;
gs_free char *filename_ask = NULL;
AddConnectionInfo *info;
gs_unref_object NMConnection *connection = NULL;
NMVpnEditorPlugin *plugin;
gs_free char *service_type = NULL;
@ -8943,18 +8946,13 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
NMC_RETURN (nmc, NMC_RESULT_ERROR_UNKNOWN);
}
info = g_malloc0 (sizeof (AddConnectionInfo));
info->nmc = nmc;
info->con_name = g_strdup (nm_connection_get_id (connection));
/* Add the new imported connection to NetworkManager */
add_new_connection (!temporary,
nmc->client,
connection,
add_connection_cb,
info);
add_connection (nmc->client,
connection,
temporary,
add_connection_cb,
_add_connection_info_new (nmc, NULL, connection));
nmc->should_wait++;
return nmc->return_value;
}