cli: compare nmcli and NM versions

nmcli gets NM version and compares it with its own and complains
when they differ. This is to indicate that the results are not reliable,
because the API could differ. '--nocheck' switches the checks off.
This commit is contained in:
Jiří Klimeš
2011-02-16 17:36:50 +01:00
parent 25ae47598c
commit a9a30eb08c
7 changed files with 214 additions and 95 deletions

View File

@@ -176,6 +176,15 @@ usage (void)
" down id <id> | uuid <id>\n")); " down id <id> | uuid <id>\n"));
} }
/* The real commands that do something - i.e. not 'help', etc. */
static const char *real_con_commands[] = {
"list",
"status",
"up",
"down",
NULL
};
/* quit main loop */ /* quit main loop */
static void static void
quit (void) quit (void)
@@ -1655,14 +1664,10 @@ do_connection_down (NmCli *nmc, int argc, char **argv)
} }
} }
/* TODO: fail gracefully if we are using an old N-M with user settings
* support */
if (active) if (active)
nm_client_deactivate_connection (nmc->client, active); nm_client_deactivate_connection (nmc->client, active);
else { else
fprintf (stderr, _("Warning: Connection not active\n")); fprintf (stderr, _("Warning: Connection not active\n"));
}
sleep (1); /* Don't quit immediatelly and give NM time to check our permissions */ sleep (1); /* Don't quit immediatelly and give NM time to check our permissions */
error: error:
@@ -1670,66 +1675,91 @@ error:
return nmc->return_value; return nmc->return_value;
} }
static NMCResultCode
parse_cmd (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
if (argc == 0) {
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
goto opt_error;
nmc->return_value = do_connections_list (nmc, argc, argv);
} else {
if (matches (*argv, "list") == 0) {
nmc->return_value = do_connections_list (nmc, argc-1, argv+1);
}
else if (matches(*argv, "status") == 0) {
if (!nmc_terse_option_check (nmc->print_output, nmc->required_fields, &error))
goto opt_error;
nmc->return_value = do_connections_status (nmc, argc-1, argv+1);
}
else if (matches(*argv, "up") == 0) {
nmc->return_value = do_connection_up (nmc, argc-1, argv+1);
}
else if (matches(*argv, "down") == 0) {
nmc->return_value = do_connection_down (nmc, argc-1, argv+1);
}
else if (matches (*argv, "help") == 0) {
usage ();
nmc->should_wait = FALSE;
} else {
usage ();
g_string_printf (nmc->return_text, _("Error: 'con' command '%s' is not valid."), *argv);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
nmc->should_wait = FALSE;
}
}
return nmc->return_value;
opt_error:
g_string_printf (nmc->return_text, _("Error: %s."), error->message);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
nmc->should_wait = FALSE;
g_error_free (error);
return nmc->return_value;
}
/* callback called when connections are obtained from the settings service */ /* callback called when connections are obtained from the settings service */
static void static void
get_connections_cb (NMRemoteSettings *settings, gpointer user_data) get_connections_cb (NMRemoteSettings *settings, gpointer user_data)
{ {
ArgsInfo *args = (ArgsInfo *) user_data; ArgsInfo *args = (ArgsInfo *) user_data;
GError *error = NULL;
/* Get the connection list */
args->nmc->system_connections = nm_remote_settings_list_connections (settings); args->nmc->system_connections = nm_remote_settings_list_connections (settings);
if (args->argc == 0) { parse_cmd (args->nmc, args->argc, args->argv);
if (!nmc_terse_option_check (args->nmc->print_output, args->nmc->required_fields, &error))
goto opt_error;
args->nmc->return_value = do_connections_list (args->nmc, args->argc, args->argv);
} else {
if (matches (*args->argv, "list") == 0) {
args->nmc->return_value = do_connections_list (args->nmc, args->argc-1, args->argv+1);
}
else if (matches(*args->argv, "status") == 0) {
if (!nmc_terse_option_check (args->nmc->print_output, args->nmc->required_fields, &error))
goto opt_error;
args->nmc->return_value = do_connections_status (args->nmc, args->argc-1, args->argv+1);
}
else if (matches(*args->argv, "up") == 0) {
args->nmc->return_value = do_connection_up (args->nmc, args->argc-1, args->argv+1);
}
else if (matches(*args->argv, "down") == 0) {
args->nmc->return_value = do_connection_down (args->nmc, args->argc-1, args->argv+1);
}
else if (matches (*args->argv, "help") == 0) {
usage ();
args->nmc->should_wait = FALSE;
} else {
usage ();
g_string_printf (args->nmc->return_text, _("Error: 'con' command '%s' is not valid."), *args->argv);
args->nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
args->nmc->should_wait = FALSE;
}
}
if (!args->nmc->should_wait) if (!args->nmc->should_wait)
quit (); quit ();
return;
opt_error:
g_string_printf (args->nmc->return_text, _("Error: %s."), error->message);
args->nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
args->nmc->should_wait = FALSE;
g_error_free (error);
quit ();
return;
} }
/* Entry point function for connections-related commands: 'nmcli con' */ /* Entry point function for connections-related commands: 'nmcli con' */
NMCResultCode NMCResultCode
do_connections (NmCli *nmc, int argc, char **argv) do_connections (NmCli *nmc, int argc, char **argv)
{ {
DBusGConnection *bus; DBusGConnection *bus;
GError *error = NULL; GError *error = NULL;
int i = 0;
gboolean real_cmd = FALSE;
if (argc == 0)
real_cmd = TRUE;
else {
while (real_con_commands[i] && matches (*argv, real_con_commands[i]) != 0)
i++;
if (real_con_commands[i] != NULL)
real_cmd = TRUE;
}
if (!real_cmd) {
/* no real execution command - no need to get connections */
return parse_cmd (nmc, argc, argv);
} else {
if (!nmc_versions_match (nmc))
return nmc->return_value;
nmc->should_wait = TRUE; nmc->should_wait = TRUE;
@@ -1773,4 +1803,5 @@ do_connections (NmCli *nmc, int argc, char **argv)
* We need to wait for signals that connections are read. * We need to wait for signals that connections are read.
*/ */
return NMC_RESULT_SUCCESS; return NMC_RESULT_SUCCESS;
}
} }

View File

@@ -1007,6 +1007,9 @@ do_devices_status (NmCli *nmc, int argc, char **argv)
goto error; goto error;
} }
if (!nmc_versions_match (nmc))
goto error;
/* Print headers */ /* Print headers */
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
nmc->print_fields.header_name = _("Status of devices"); nmc->print_fields.header_name = _("Status of devices");
@@ -1066,6 +1069,9 @@ do_devices_list (NmCli *nmc, int argc, char **argv)
goto error; goto error;
} }
if (!nmc_versions_match (nmc))
goto error;
nmc->get_client (nmc); nmc->get_client (nmc);
devices = nm_client_get_devices (nmc->client); devices = nm_client_get_devices (nmc->client);
@@ -1216,6 +1222,9 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv)
goto error; goto error;
} }
if (!nmc_versions_match (nmc))
goto error;
nmc->get_client (nmc); nmc->get_client (nmc);
devices = nm_client_get_devices (nmc->client); devices = nm_client_get_devices (nmc->client);
for (i = 0; devices && (i < devices->len); i++) { for (i = 0; devices && (i < devices->len); i++) {
@@ -1341,6 +1350,9 @@ do_device_wifi_list (NmCli *nmc, int argc, char **argv)
goto error; goto error;
} }
if (!nmc_versions_match (nmc))
goto error;
/* Print headers */ /* Print headers */
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
nmc->print_fields.header_name = _("WiFi scan list"); nmc->print_fields.header_name = _("WiFi scan list");
@@ -1525,12 +1537,6 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
argv++; argv++;
} }
/* create NMClient */
if (!nmc->get_client (nmc))
goto error;
devices = nm_client_get_devices (nmc->client);
if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0) if (!nmc->required_fields || strcasecmp (nmc->required_fields, "common") == 0)
fields_str = fields_common; fields_str = fields_common;
else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0) else if (!nmc->required_fields || strcasecmp (nmc->required_fields, "all") == 0)
@@ -1551,9 +1557,27 @@ do_device_wimax_list (NmCli *nmc, int argc, char **argv)
goto error; goto error;
} }
if (!nmc_is_nm_running (nmc, &error)) {
if (error) {
g_string_printf (nmc->return_text, _("Error: Can't find out if NetworkManager is running: %s."), error->message);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
g_error_free (error);
} else {
g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
}
goto error;
}
if (!nmc_versions_match (nmc))
goto error;
/* Print headers */
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES; nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
nmc->print_fields.header_name = _("WiMAX NSP list"); nmc->print_fields.header_name = _("WiMAX NSP list");
nmc->get_client (nmc);
devices = nm_client_get_devices (nmc->client);
if (iface) { if (iface) {
/* Device specified - list only NSPs of this interface */ /* Device specified - list only NSPs of this interface */
for (i = 0; devices && (i < devices->len); i++) { for (i = 0; devices && (i < devices->len); i++) {

View File

@@ -156,12 +156,11 @@ show_nm_status (NmCli *nmc)
return nmc->return_value; return nmc->return_value;
} }
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
nmc->print_fields.header_name = _("NetworkManager status");
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
nm_running = nmc_is_nm_running (nmc, NULL); nm_running = nmc_is_nm_running (nmc, NULL);
if (nm_running) { if (nm_running) {
if (!nmc_versions_match (nmc))
goto error;
nmc->get_client (nmc); /* create NMClient */ nmc->get_client (nmc); /* create NMClient */
state = nm_client_get_state (nmc->client); state = nm_client_get_state (nmc->client);
net_enabled_str = nm_client_networking_get_enabled (nmc->client) ? _("enabled") : _("disabled"); net_enabled_str = nm_client_networking_get_enabled (nmc->client) ? _("enabled") : _("disabled");
@@ -183,6 +182,10 @@ show_nm_status (NmCli *nmc)
#endif #endif
} }
nmc->print_fields.flags = multiline_flag | mode_flag | escape_flag | NMC_PF_FLAG_MAIN_HEADER_ADD | NMC_PF_FLAG_FIELD_NAMES;
nmc->print_fields.header_name = _("NetworkManager status");
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print header */
nmc->allowed_fields[0].value = nm_running ? _("running") : _("not running"); nmc->allowed_fields[0].value = nm_running ? _("running") : _("not running");
nmc->allowed_fields[1].value = nm_client_get_version (nmc->client); nmc->allowed_fields[1].value = nm_client_get_version (nmc->client);
nmc->allowed_fields[2].value = nm_state_to_string (state); nmc->allowed_fields[2].value = nm_state_to_string (state);
@@ -200,6 +203,9 @@ show_nm_status (NmCli *nmc)
print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */ print_fields (nmc->print_fields, nmc->allowed_fields); /* Print values */
return NMC_RESULT_SUCCESS; return NMC_RESULT_SUCCESS;
error:
return nmc->return_value;
} }
/* libnm-glib doesn't provide API fro Sleep method - implement D-Bus call ourselves */ /* libnm-glib doesn't provide API fro Sleep method - implement D-Bus call ourselves */

View File

@@ -68,6 +68,7 @@ usage (const char *prog_name)
" -m[ode] tabular|multiline output mode\n" " -m[ode] tabular|multiline output mode\n"
" -f[ields] <field1,field2,...>|all|common specify fields to output\n" " -f[ields] <field1,field2,...>|all|common specify fields to output\n"
" -e[scape] yes|no escape columns separators in values\n" " -e[scape] yes|no escape columns separators in values\n"
" -n[ocheck] don't check nmcli and NetworkManager versions\n"
" -v[ersion] show program version\n" " -v[ersion] show program version\n"
" -h[elp] print this help\n\n" " -h[elp] print this help\n\n"
"OBJECT\n" "OBJECT\n"
@@ -200,6 +201,8 @@ parse_command_line (NmCli *nmc, int argc, char **argv)
return nmc->return_value; return nmc->return_value;
} }
nmc->required_fields = g_strdup (argv[1]); nmc->required_fields = g_strdup (argv[1]);
} else if (matches (opt, "-nocheck") == 0) {
nmc->nocheck_ver = TRUE;
} else if (matches (opt, "-version") == 0) { } else if (matches (opt, "-version") == 0) {
printf (_("nmcli tool, version %s\n"), NMCLI_VERSION); printf (_("nmcli tool, version %s\n"), NMCLI_VERSION);
return NMC_RESULT_SUCCESS; return NMC_RESULT_SUCCESS;
@@ -284,6 +287,7 @@ nmc_init (NmCli *nmc)
nmc->required_fields = NULL; nmc->required_fields = NULL;
nmc->allowed_fields = NULL; nmc->allowed_fields = NULL;
memset (&nmc->print_fields, '\0', sizeof (NmcPrintFields)); memset (&nmc->print_fields, '\0', sizeof (NmcPrintFields));
nmc->nocheck_ver = FALSE;
} }
static void static void

View File

@@ -49,7 +49,10 @@ typedef enum {
NMC_RESULT_ERROR_DEV_DISCONNECT = 6, NMC_RESULT_ERROR_DEV_DISCONNECT = 6,
/* NetworkManager is not running */ /* NetworkManager is not running */
NMC_RESULT_ERROR_NM_NOT_RUNNING = 7 NMC_RESULT_ERROR_NM_NOT_RUNNING = 7,
/* nmcli and NetworkManager versions mismatch */
NMC_RESULT_ERROR_VERSIONS_MISMATCH = 8
} NMCResultCode; } NMCResultCode;
typedef enum { typedef enum {
@@ -107,6 +110,7 @@ typedef struct _NmCli {
char *required_fields; /* Required fields in output: '--fields' option */ char *required_fields; /* Required fields in output: '--fields' option */
NmcOutputField *allowed_fields; /* Array of allowed fields for particular commands */ NmcOutputField *allowed_fields; /* Array of allowed fields for particular commands */
NmcPrintFields print_fields; /* Structure with field indices to print */ NmcPrintFields print_fields; /* Structure with field indices to print */
gboolean nocheck_ver; /* Don't check nmcli and NM versions: option '--nocheck' */
} NmCli; } NmCli;
#endif /* NMC_NMCLI_H */ #endif /* NMC_NMCLI_H */

View File

@@ -17,6 +17,9 @@
* (C) Copyright 2010 - 2011 Red Hat, Inc. * (C) Copyright 2010 - 2011 Red Hat, Inc.
*/ */
/* Generated configuration file */
#include "config.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -351,3 +354,49 @@ done:
return has_owner; return has_owner;
} }
/*
* Compare versions of nmcli and NM daemon.
* Return: TRUE - the versions match (when only major and minor match, print a warning)
* FALSE - versions mismatch
*/
gboolean
nmc_versions_match (NmCli *nmc)
{
const char *nm_ver = NULL;
const char *dot;
gboolean match = FALSE;
g_return_val_if_fail (nmc != NULL, FALSE);
/* --nocheck option - don't compare the versions */
if (nmc->nocheck_ver)
return TRUE;
nmc->get_client (nmc);
nm_ver = nm_client_get_version (nmc->client);
if (nm_ver) {
if (!strcmp (nm_ver, VERSION))
match = TRUE;
else {
dot = strchr (nm_ver, '.');
if (dot) {
dot = strchr (dot + 1, '.');
if (dot && !strncmp (nm_ver, VERSION, dot-nm_ver)) {
fprintf(stderr,
_("Warning: nmcli (%s) and NetworkManager (%s) versions don't match. Use --nocheck to suppress the warning.\n"),
VERSION, nm_ver);
match = TRUE;
}
}
}
}
if (!match) {
g_string_printf (nmc->return_text, _("Error: nmcli (%s) and NetworkManager (%s) versions don't match. Force execution using --nocheck, but the results are unpredictable."),
VERSION, nm_ver ? nm_ver : _("unknown"));
nmc->return_value = NMC_RESULT_ERROR_VERSIONS_MISMATCH;
}
return match;
}

View File

@@ -33,5 +33,6 @@ GArray *parse_output_fields (const char *fields_str, const NmcOutputField fields
gboolean nmc_terse_option_check (NMCPrintOutput print_output, const char *fields, GError **error); gboolean nmc_terse_option_check (NMCPrintOutput print_output, const char *fields, GError **error);
void print_fields (const NmcPrintFields fields, const NmcOutputField field_values[]); void print_fields (const NmcPrintFields fields, const NmcOutputField field_values[]);
gboolean nmc_is_nm_running (NmCli *nmc, GError **error); gboolean nmc_is_nm_running (NmCli *nmc, GError **error);
gboolean nmc_versions_match (NmCli *nmc);
#endif /* NMC_UTILS_H */ #endif /* NMC_UTILS_H */