mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-15 12:34:55 +00:00
cli: move utils function from common.h to nm-meta-setting-desc.c
These functions are only used by nm-meta-setting-desc.c. Make them internal. Unfortunately, they are part of "common.h" which cannot be used without the rest of nmcli. Still todo.
This commit is contained in:
parent
b5c8622ad3
commit
23298bfc88
|
@ -3117,10 +3117,15 @@ if BUILD_NMCLI
|
|||
bin_PROGRAMS += clients/cli/nmcli
|
||||
|
||||
clients_cli_nmcli_SOURCES = \
|
||||
\
|
||||
shared/nm-utils/nm-shared-utils.c \
|
||||
shared/nm-utils/nm-shared-utils.h \
|
||||
\
|
||||
shared/nm-meta-setting.c \
|
||||
shared/nm-meta-setting.h \
|
||||
\
|
||||
clients/common/nm-client-utils.c \
|
||||
clients/common/nm-client-utils.h \
|
||||
clients/common/nm-meta-setting-desc.c \
|
||||
clients/common/nm-meta-setting-desc.h \
|
||||
\
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include <readline/history.h>
|
||||
|
||||
#include "nm-vpn-helpers.h"
|
||||
#include "nm-client-utils.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
@ -346,193 +348,6 @@ print_dhcp6_config (NMDhcpConfig *dhcp6,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse IP address from string to NMIPAddress stucture.
|
||||
* ip_str is the IP address in the form address/prefix
|
||||
*/
|
||||
NMIPAddress *
|
||||
nmc_parse_and_build_address (int family, const char *ip_str, GError **error)
|
||||
{
|
||||
int max_prefix = (family == AF_INET) ? 32 : 128;
|
||||
NMIPAddress *addr = NULL;
|
||||
const char *ip;
|
||||
char *tmp;
|
||||
char *plen;
|
||||
long int prefix;
|
||||
GError *local = NULL;
|
||||
|
||||
g_return_val_if_fail (ip_str != NULL, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
tmp = g_strdup (ip_str);
|
||||
plen = strchr (tmp, '/'); /* prefix delimiter */
|
||||
if (plen)
|
||||
*plen++ = '\0';
|
||||
|
||||
ip = tmp;
|
||||
|
||||
prefix = max_prefix;
|
||||
if (plen) {
|
||||
if (!nmc_string_to_int (plen, TRUE, 1, max_prefix, &prefix)) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("invalid prefix '%s'; <1-%d> allowed"), plen, max_prefix);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
addr = nm_ip_address_new (family, ip, (guint32) prefix, &local);
|
||||
if (!addr) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("invalid IP address: %s"), local->message);
|
||||
g_clear_error (&local);
|
||||
}
|
||||
|
||||
finish:
|
||||
g_free (tmp);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* nmc_parse_and_build_route:
|
||||
* @family: AF_INET or AF_INET6
|
||||
* @str: route string to be parsed
|
||||
* @error: location to store GError
|
||||
*
|
||||
* Parse route from string and return an #NMIPRoute
|
||||
*
|
||||
* Returns: a new #NMIPRoute or %NULL on error
|
||||
*/
|
||||
NMIPRoute *
|
||||
nmc_parse_and_build_route (int family,
|
||||
const char *str,
|
||||
GError **error)
|
||||
{
|
||||
int max_prefix = (family == AF_INET) ? 32 : 128;
|
||||
char *plen = NULL;
|
||||
const char *next_hop = NULL;
|
||||
const char *canon_dest;
|
||||
long int prefix = max_prefix;
|
||||
unsigned long int tmp_ulong;
|
||||
NMIPRoute *route = NULL;
|
||||
gboolean success = FALSE;
|
||||
GError *local = NULL;
|
||||
gint64 metric = -1;
|
||||
guint i, len;
|
||||
gs_strfreev char **routev = NULL;
|
||||
gs_free char *value = NULL;
|
||||
gs_free char *dest = NULL;
|
||||
gs_unref_hashtable GHashTable *attrs = NULL;
|
||||
GHashTable *tmp_attrs;
|
||||
|
||||
g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
|
||||
g_return_val_if_fail (str, FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
value = g_strdup (str);
|
||||
routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
|
||||
len = g_strv_length (routev);
|
||||
if (len < 1) {
|
||||
g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric] [attr=val] [attr=val])"),
|
||||
str);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
dest = g_strdup (routev[0]);
|
||||
plen = strchr (dest, '/'); /* prefix delimiter */
|
||||
if (plen)
|
||||
*plen++ = '\0';
|
||||
|
||||
if (plen) {
|
||||
if (!nmc_string_to_int (plen, TRUE, 1, max_prefix, &prefix)) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("invalid prefix '%s'; <1-%d> allowed"),
|
||||
plen, max_prefix);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < len; i++) {
|
||||
if (nm_utils_ipaddr_valid (family, routev[i])) {
|
||||
if (metric != -1 || attrs) {
|
||||
g_set_error (error, 1, 0, _("the next hop ('%s') must be first"), routev[i]);
|
||||
goto finish;
|
||||
}
|
||||
next_hop = routev[i];
|
||||
} else if (nmc_string_to_uint (routev[i], TRUE, 0, G_MAXUINT32, &tmp_ulong)) {
|
||||
if (attrs) {
|
||||
g_set_error (error, 1, 0, _("the metric ('%s') must be before attributes"), routev[i]);
|
||||
goto finish;
|
||||
}
|
||||
metric = tmp_ulong;
|
||||
} else if (strchr (routev[i], '=')) {
|
||||
GHashTableIter iter;
|
||||
char *iter_key;
|
||||
GVariant *iter_value;
|
||||
|
||||
tmp_attrs = nm_utils_parse_variant_attributes (routev[i], ' ', '=', FALSE,
|
||||
nm_ip_route_get_variant_attribute_spec(),
|
||||
error);
|
||||
if (!tmp_attrs) {
|
||||
g_prefix_error (error, "invalid option '%s': ", routev[i]);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!attrs)
|
||||
attrs = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
g_hash_table_iter_init (&iter, tmp_attrs);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &iter_key, (gpointer *) &iter_value)) {
|
||||
if (!nm_ip_route_attribute_validate (iter_key, iter_value, family, NULL, error)) {
|
||||
g_prefix_error (error, "%s: ", iter_key);
|
||||
g_hash_table_unref (tmp_attrs);
|
||||
goto finish;
|
||||
}
|
||||
g_hash_table_insert (attrs, iter_key, iter_value);
|
||||
g_hash_table_iter_steal (&iter);
|
||||
}
|
||||
g_hash_table_unref (tmp_attrs);
|
||||
} else {
|
||||
g_set_error (error, 1, 0, _("unrecognized option '%s'"), routev[i]);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &local);
|
||||
if (!route) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("invalid route: %s"), local->message);
|
||||
g_clear_error (&local);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* We don't accept default routes as NetworkManager handles it
|
||||
* itself. But we have to check this after @route has normalized the
|
||||
* dest string.
|
||||
*/
|
||||
canon_dest = nm_ip_route_get_dest (route);
|
||||
if (!strcmp (canon_dest, "0.0.0.0") || !strcmp (canon_dest, "::")) {
|
||||
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("default route cannot be added (NetworkManager handles it by itself)"));
|
||||
g_clear_pointer (&route, nm_ip_route_unref);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (attrs) {
|
||||
GHashTableIter iter;
|
||||
char *name;
|
||||
GVariant *variant;
|
||||
|
||||
g_hash_table_iter_init (&iter, attrs);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant))
|
||||
nm_ip_route_set_attribute (route, name, variant);
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
|
||||
finish:
|
||||
return route;
|
||||
}
|
||||
|
||||
const char *
|
||||
nmc_device_state_to_string (NMDeviceState state)
|
||||
{
|
||||
|
@ -782,240 +597,6 @@ nmc_device_reason_to_string (NMDeviceStateReason reason)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* Max priority values from libnm-core/nm-setting-vlan.c */
|
||||
#define MAX_SKB_PRIO G_MAXUINT32
|
||||
#define MAX_8021P_PRIO 7 /* Max 802.1p priority */
|
||||
|
||||
/*
|
||||
* Parse VLAN priority mappings from the following format: 2:1,3:4,7:3
|
||||
* and verify if the priority numbers are valid
|
||||
*
|
||||
* Return: string array with split maps, or NULL on error
|
||||
* Caller is responsible for freeing the array.
|
||||
*/
|
||||
char **
|
||||
nmc_vlan_parse_priority_maps (const char *priority_map,
|
||||
NMVlanPriorityMap map_type,
|
||||
GError **error)
|
||||
{
|
||||
char **mapping = NULL, **iter;
|
||||
unsigned long from, to, from_max, to_max;
|
||||
|
||||
g_return_val_if_fail (priority_map != NULL, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
if (map_type == NM_VLAN_INGRESS_MAP) {
|
||||
from_max = MAX_8021P_PRIO;
|
||||
to_max = MAX_SKB_PRIO;
|
||||
} else {
|
||||
from_max = MAX_SKB_PRIO;
|
||||
to_max = MAX_8021P_PRIO;
|
||||
}
|
||||
|
||||
mapping = g_strsplit (priority_map, ",", 0);
|
||||
for (iter = mapping; iter && *iter; iter++) {
|
||||
char *left, *right;
|
||||
|
||||
left = g_strstrip (*iter);
|
||||
right = strchr (left, ':');
|
||||
if (!right) {
|
||||
g_set_error (error, 1, 0, _("invalid priority map '%s'"), *iter);
|
||||
g_strfreev (mapping);
|
||||
return NULL;
|
||||
}
|
||||
*right++ = '\0';
|
||||
|
||||
if (!nmc_string_to_uint (left, TRUE, 0, from_max, &from)) {
|
||||
g_set_error (error, 1, 0, _("priority '%s' is not valid (<0-%ld>)"),
|
||||
left, from_max);
|
||||
g_strfreev (mapping);
|
||||
return NULL;
|
||||
}
|
||||
if (!nmc_string_to_uint (right, TRUE, 0, to_max, &to)) {
|
||||
g_set_error (error, 1, 0, _("priority '%s' is not valid (<0-%ld>)"),
|
||||
right, to_max);
|
||||
g_strfreev (mapping);
|
||||
return NULL;
|
||||
}
|
||||
*(right-1) = ':'; /* Put back ':' */
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
const char *
|
||||
nmc_bond_validate_mode (const char *mode, GError **error)
|
||||
{
|
||||
unsigned long mode_int;
|
||||
static const char *valid_modes[] = { "balance-rr",
|
||||
"active-backup",
|
||||
"balance-xor",
|
||||
"broadcast",
|
||||
"802.3ad",
|
||||
"balance-tlb",
|
||||
"balance-alb",
|
||||
NULL };
|
||||
if (nmc_string_to_uint (mode, TRUE, 0, 6, &mode_int)) {
|
||||
/* Translate bonding mode numbers to mode names:
|
||||
* https://www.kernel.org/doc/Documentation/networking/bonding.txt
|
||||
*/
|
||||
return valid_modes[mode_int];
|
||||
} else
|
||||
return nmc_string_is_valid (mode, valid_modes, error);
|
||||
}
|
||||
|
||||
/*
|
||||
* nmc_team_check_config:
|
||||
* @config: file name with team config, or raw team JSON config data
|
||||
* @out_config: raw team JSON config data
|
||||
* The value must be freed with g_free().
|
||||
* @error: location to store error, or %NUL
|
||||
*
|
||||
* Check team config from @config parameter and return the checked
|
||||
* config in @out_config.
|
||||
*
|
||||
* Returns: %TRUE if the config is valid, %FALSE if it is invalid
|
||||
*/
|
||||
gboolean
|
||||
nmc_team_check_config (const char *config, char **out_config, GError **error)
|
||||
{
|
||||
enum {
|
||||
_TEAM_CONFIG_TYPE_GUESS,
|
||||
_TEAM_CONFIG_TYPE_FILE,
|
||||
_TEAM_CONFIG_TYPE_JSON,
|
||||
} desired_type = _TEAM_CONFIG_TYPE_GUESS;
|
||||
const char *filename = NULL;
|
||||
size_t c_len = 0;
|
||||
gs_free char *config_clone = NULL;
|
||||
|
||||
*out_config = NULL;
|
||||
|
||||
if (!config || !config[0])
|
||||
return TRUE;
|
||||
|
||||
if (g_str_has_prefix (config, "file://")) {
|
||||
config += NM_STRLEN ("file://");
|
||||
desired_type = _TEAM_CONFIG_TYPE_FILE;
|
||||
} else if (g_str_has_prefix (config, "json://")) {
|
||||
config += NM_STRLEN ("json://");
|
||||
desired_type = _TEAM_CONFIG_TYPE_JSON;
|
||||
}
|
||||
|
||||
if (NM_IN_SET (desired_type, _TEAM_CONFIG_TYPE_FILE, _TEAM_CONFIG_TYPE_GUESS)) {
|
||||
gs_free char *contents = NULL;
|
||||
|
||||
if (!g_file_get_contents (config, &contents, &c_len, NULL)) {
|
||||
if (desired_type == _TEAM_CONFIG_TYPE_FILE) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("cannot read team config from file '%s'"),
|
||||
config);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (c_len != strlen (contents)) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("team config file '%s' contains non-valid utf-8"),
|
||||
config);
|
||||
return FALSE;
|
||||
}
|
||||
filename = config;
|
||||
config = config_clone = g_steal_pointer (&contents);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nm_utils_is_json_object (config, NULL)) {
|
||||
if (filename) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("'%s' does not contain a valid team configuration"), filename);
|
||||
} else {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("team configuration must be a JSON object"));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*out_config = (config == config_clone)
|
||||
? g_steal_pointer (&config_clone)
|
||||
: g_strdup (config);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* nmc_proxy_check_script:
|
||||
* @script: file name with PAC script, or raw PAC Script data
|
||||
* @out_script: raw PAC Script (with removed new-line characters)
|
||||
* @error: location to store error, or %NULL
|
||||
*
|
||||
* Check PAC Script from @script parameter and return the checked/sanitized
|
||||
* config in @out_script.
|
||||
*
|
||||
* Returns: %TRUE if the script is valid, %FALSE if it is invalid
|
||||
*/
|
||||
gboolean
|
||||
nmc_proxy_check_script (const char *script, char **out_script, GError **error)
|
||||
{
|
||||
enum {
|
||||
_PAC_SCRIPT_TYPE_GUESS,
|
||||
_PAC_SCRIPT_TYPE_FILE,
|
||||
_PAC_SCRIPT_TYPE_JSON,
|
||||
} desired_type = _PAC_SCRIPT_TYPE_GUESS;
|
||||
const char *filename = NULL;
|
||||
size_t c_len = 0;
|
||||
gs_free char *script_clone = NULL;
|
||||
|
||||
*out_script = NULL;
|
||||
|
||||
if (!script || !script[0])
|
||||
return TRUE;
|
||||
|
||||
if (g_str_has_prefix (script, "file://")) {
|
||||
script += NM_STRLEN ("file://");
|
||||
desired_type = _PAC_SCRIPT_TYPE_FILE;
|
||||
} else if (g_str_has_prefix (script, "js://")) {
|
||||
script += NM_STRLEN ("js://");
|
||||
desired_type = _PAC_SCRIPT_TYPE_JSON;
|
||||
}
|
||||
|
||||
if (NM_IN_SET (desired_type, _PAC_SCRIPT_TYPE_FILE, _PAC_SCRIPT_TYPE_GUESS)) {
|
||||
gs_free char *contents = NULL;
|
||||
|
||||
if (!g_file_get_contents (script, &contents, &c_len, NULL)) {
|
||||
if (desired_type == _PAC_SCRIPT_TYPE_FILE) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("cannot read pac-script from file '%s'"),
|
||||
script);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (c_len != strlen (contents)) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("file '%s' contains non-valid utf-8"),
|
||||
script);
|
||||
return FALSE;
|
||||
}
|
||||
filename = script;
|
||||
script = script_clone = g_steal_pointer (&contents);
|
||||
}
|
||||
}
|
||||
|
||||
if ( !strstr (script, "FindProxyForURL")
|
||||
|| !g_utf8_validate (script, -1, NULL)) {
|
||||
if (filename) {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("'%s' does not contain a valid PAC Script"), filename);
|
||||
} else {
|
||||
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_USER_INPUT,
|
||||
_("Not a valid PAC Script"));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*out_script = (script == script_clone)
|
||||
? g_steal_pointer (&script_clone)
|
||||
: g_strdup (script);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* nmc_find_connection:
|
||||
* @connections: array of NMConnections to search in
|
||||
|
|
|
@ -30,22 +30,10 @@ gboolean print_ip6_config (NMIPConfig *cfg6, NmCli *nmc, const char *group_prefi
|
|||
gboolean print_dhcp4_config (NMDhcpConfig *dhcp4, NmCli *nmc, const char *group_prefix, const char *one_field);
|
||||
gboolean print_dhcp6_config (NMDhcpConfig *dhcp6, NmCli *nmc, const char *group_prefix, const char *one_field);
|
||||
|
||||
NMIPAddress *nmc_parse_and_build_address (int family, const char *ip_str, GError **error);
|
||||
NMIPRoute *nmc_parse_and_build_route (int family, const char *str, GError **error);
|
||||
|
||||
const char * nmc_device_state_to_string (NMDeviceState state);
|
||||
const char * nmc_device_reason_to_string (NMDeviceStateReason reason);
|
||||
const char * nmc_device_metered_to_string (NMMetered value);
|
||||
|
||||
char **
|
||||
nmc_vlan_parse_priority_maps (const char *priority_map,
|
||||
NMVlanPriorityMap map_type,
|
||||
GError **error);
|
||||
|
||||
const char *nmc_bond_validate_mode (const char *mode, GError **error);
|
||||
gboolean nmc_team_check_config (const char *config, char **out_config, GError **error);
|
||||
gboolean nmc_proxy_check_script (const char *script, char **out_script, GError **error);
|
||||
|
||||
NMConnection *nmc_find_connection (const GPtrArray *connections,
|
||||
const char *filter_type,
|
||||
const char *filter_val,
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#include "nm-client-utils.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "common.h"
|
||||
#include "settings.h"
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
#include <readline/readline.h>
|
||||
|
||||
#include "nm-secret-agent-simple.h"
|
||||
#include "nm-client-utils.h"
|
||||
|
||||
#include "polkit-agent.h"
|
||||
#include "utils.h"
|
||||
#include "common.h"
|
||||
|
|
|
@ -22,13 +22,15 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nm-common-macros.h"
|
||||
|
||||
#include "nm-client-utils.h"
|
||||
|
||||
#include "polkit-agent.h"
|
||||
#include "utils.h"
|
||||
#include "common.h"
|
||||
#include "general.h"
|
||||
#include "common.h"
|
||||
#include "nm-common-macros.h"
|
||||
|
||||
#include "devices.h"
|
||||
#include "connections.h"
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@
|
|||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#include "nm-client-utils.h"
|
||||
|
||||
#include "polkit-agent.h"
|
||||
#include "nmcli.h"
|
||||
#include "utils.h"
|
||||
|
|
|
@ -25,9 +25,12 @@
|
|||
#include <arpa/inet.h>
|
||||
|
||||
#include "nm-common-macros.h"
|
||||
|
||||
#include "nm-client-utils.h"
|
||||
#include "nm-vpn-helpers.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "common.h"
|
||||
#include "nm-vpn-helpers.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
@ -27,19 +27,12 @@
|
|||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "nm-client-utils.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include "common.h"
|
||||
#include "settings.h"
|
||||
|
||||
gboolean
|
||||
matches (const char *cmd, const char *pattern)
|
||||
{
|
||||
size_t len = strlen (cmd);
|
||||
if (!len || len > strlen (pattern))
|
||||
return FALSE;
|
||||
return memcmp (pattern, cmd, len) == 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_global_arg (NmCli *nmc, const char *arg)
|
||||
{
|
||||
|
@ -426,137 +419,6 @@ nmc_filter_out_colors (const char *str)
|
|||
return filtered;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert string to signed integer.
|
||||
* If required, the resulting number is checked to be in the <min,max> range.
|
||||
*/
|
||||
gboolean
|
||||
nmc_string_to_int_base (const char *str,
|
||||
int base,
|
||||
gboolean range_check,
|
||||
long int min,
|
||||
long int max,
|
||||
long int *value)
|
||||
{
|
||||
char *end;
|
||||
long int tmp;
|
||||
|
||||
errno = 0;
|
||||
tmp = strtol (str, &end, base);
|
||||
if (errno || *end != '\0' || (range_check && (tmp < min || tmp > max))) {
|
||||
return FALSE;
|
||||
}
|
||||
*value = tmp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert string to unsigned integer.
|
||||
* If required, the resulting number is checked to be in the <min,max> range.
|
||||
*/
|
||||
gboolean
|
||||
nmc_string_to_uint_base (const char *str,
|
||||
int base,
|
||||
gboolean range_check,
|
||||
unsigned long int min,
|
||||
unsigned long int max,
|
||||
unsigned long int *value)
|
||||
{
|
||||
char *end;
|
||||
unsigned long int tmp;
|
||||
|
||||
errno = 0;
|
||||
tmp = strtoul (str, &end, base);
|
||||
if (errno || *end != '\0' || (range_check && (tmp < min || tmp > max))) {
|
||||
return FALSE;
|
||||
}
|
||||
*value = tmp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_string_to_int (const char *str,
|
||||
gboolean range_check,
|
||||
long int min,
|
||||
long int max,
|
||||
long int *value)
|
||||
{
|
||||
return nmc_string_to_int_base (str, 10, range_check, min, max, value);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_string_to_uint (const char *str,
|
||||
gboolean range_check,
|
||||
unsigned long int min,
|
||||
unsigned long int max,
|
||||
unsigned long int *value)
|
||||
{
|
||||
return nmc_string_to_uint_base (str, 10, range_check, min, max, value);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error)
|
||||
{
|
||||
const char *s_true[] = { "true", "yes", "on", NULL };
|
||||
const char *s_false[] = { "false", "no", "off", NULL };
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (g_strcmp0 (str, "o") == 0) {
|
||||
g_set_error (error, 1, 0,
|
||||
/* Translators: the first %s is the partial value entered by
|
||||
* the user, the second %s a list of compatible values.
|
||||
*/
|
||||
_("'%s' is ambiguous (%s)"), str, "on x off");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nmc_string_is_valid (str, s_true, NULL))
|
||||
*val_bool = TRUE;
|
||||
else if (nmc_string_is_valid (str, s_false, NULL))
|
||||
*val_bool = FALSE;
|
||||
else {
|
||||
g_set_error (error, 1, 0,
|
||||
_("'%s' is not valid; use [%s] or [%s]"),
|
||||
str, "true, yes, on", "false, no, off");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_string_to_tristate (const char *str, NMCTriStateValue *val, GError **error)
|
||||
{
|
||||
const char *s_true[] = { "true", "yes", "on", NULL };
|
||||
const char *s_false[] = { "false", "no", "off", NULL };
|
||||
const char *s_unknown[] = { "unknown", NULL };
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (g_strcmp0 (str, "o") == 0) {
|
||||
g_set_error (error, 1, 0,
|
||||
/* Translators: the first %s is the partial value entered by
|
||||
* the user, the second %s a list of compatible values.
|
||||
*/
|
||||
_("'%s' is ambiguous (%s)"), str, "on x off");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nmc_string_is_valid (str, s_true, NULL))
|
||||
*val = NMC_TRI_STATE_YES;
|
||||
else if (nmc_string_is_valid (str, s_false, NULL))
|
||||
*val = NMC_TRI_STATE_NO;
|
||||
else if (nmc_string_is_valid (str, s_unknown, NULL))
|
||||
*val = NMC_TRI_STATE_UNKNOWN;
|
||||
else {
|
||||
g_set_error (error, 1, 0,
|
||||
_("'%s' is not valid; use [%s], [%s] or [%s]"),
|
||||
str, "true, yes, on", "false, no, off", "unknown");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask user for input and return the string.
|
||||
* The caller is responsible for freeing the returned string.
|
||||
|
@ -619,57 +481,6 @@ nmc_string_to_arg_array (const char *line, const char *delim, gboolean unquote,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether 'input' is contained in 'allowed' array. It performs case
|
||||
* insensitive comparison and supports shortcut strings if they are unique.
|
||||
* Returns: a pointer to found string in allowed array on success or NULL.
|
||||
* On failure: error->code : 0 - string not found; 1 - string is ambiguous
|
||||
*/
|
||||
const char *
|
||||
nmc_string_is_valid (const char *input, const char **allowed, GError **error)
|
||||
{
|
||||
const char **p;
|
||||
size_t input_ln, p_len;
|
||||
gboolean prev_match = FALSE;
|
||||
const char *ret = NULL;
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
if (!input || !*input)
|
||||
goto finish;
|
||||
|
||||
input_ln = strlen (input);
|
||||
for (p = allowed; p && *p; p++) {
|
||||
p_len = strlen (*p);
|
||||
if (g_ascii_strncasecmp (input, *p, input_ln) == 0) {
|
||||
if (input_ln == p_len) {
|
||||
ret = *p;
|
||||
break;
|
||||
}
|
||||
if (!prev_match)
|
||||
ret = *p;
|
||||
else {
|
||||
g_set_error (error, 1, 1, _("'%s' is ambiguous (%s x %s)"),
|
||||
input, ret, *p);
|
||||
return NULL;
|
||||
}
|
||||
prev_match = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
if (ret == NULL) {
|
||||
char *valid_vals = g_strjoinv (", ", (char **) allowed);
|
||||
if (!input || !*input)
|
||||
g_set_error (error, 1, 0, _("missing name, try one of [%s]"), valid_vals);
|
||||
else
|
||||
g_set_error (error, 1, 0, _("'%s' not among [%s]"), input, valid_vals);
|
||||
|
||||
g_free (valid_vals);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert string array (char **) to description string in the form of:
|
||||
* "[string1, string2, ]"
|
||||
|
@ -697,31 +508,6 @@ nmc_util_strv_for_display (const char *const*strv, gboolean brackets)
|
|||
return g_string_free (result, FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper function for g_strsplit_set() that removes empty strings
|
||||
* from the vector as they are not useful in most cases.
|
||||
*/
|
||||
char **
|
||||
nmc_strsplit_set (const char *str, const char *delimiter, int max_tokens)
|
||||
{
|
||||
char **result;
|
||||
uint i;
|
||||
uint j;
|
||||
|
||||
result = g_strsplit_set (str, delimiter, max_tokens);
|
||||
|
||||
/* remove empty strings */
|
||||
for (i = 0; result && result[i]; i++) {
|
||||
if (*(result[i]) == '\0') {
|
||||
g_free (result[i]);
|
||||
for (j = i; result[j]; j++)
|
||||
result[j] = result[j + 1];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out how many columns an UTF-8 string occupies on the screen.
|
||||
*/
|
||||
|
|
|
@ -32,43 +32,12 @@ typedef struct {
|
|||
gboolean found;
|
||||
} nmc_arg_t;
|
||||
|
||||
typedef enum {
|
||||
NMC_TRI_STATE_NO,
|
||||
NMC_TRI_STATE_YES,
|
||||
NMC_TRI_STATE_UNKNOWN,
|
||||
} NMCTriStateValue;
|
||||
|
||||
/* === Functions === */
|
||||
gboolean matches (const char *cmd, const char *pattern);
|
||||
int next_arg (NmCli *nmc, int *argc, char ***argv);
|
||||
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);
|
||||
char *ssid_to_hex (const char *str, gsize len);
|
||||
gboolean nmc_string_to_int_base (const char *str,
|
||||
int base,
|
||||
gboolean range_check,
|
||||
long int min,
|
||||
long int max,
|
||||
long int *value);
|
||||
gboolean nmc_string_to_uint_base (const char *str,
|
||||
int base,
|
||||
gboolean range_check,
|
||||
unsigned long int min,
|
||||
unsigned long int max,
|
||||
unsigned long int *value);
|
||||
gboolean nmc_string_to_int (const char *str,
|
||||
gboolean range_check,
|
||||
long int min,
|
||||
long int max,
|
||||
long int *value);
|
||||
gboolean nmc_string_to_uint (const char *str,
|
||||
gboolean range_check,
|
||||
unsigned long int min,
|
||||
unsigned long int max,
|
||||
unsigned long int *value);
|
||||
gboolean nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error);
|
||||
gboolean nmc_string_to_tristate (const char *str, NMCTriStateValue *val, GError **error);
|
||||
void nmc_terminal_erase_line (void);
|
||||
void nmc_terminal_show_progress (const char *str);
|
||||
const char *nmc_term_color_sequence (NmcTermColor color);
|
||||
|
|
239
clients/common/nm-client-utils.c
Normal file
239
clients/common/nm-client-utils.c
Normal file
|
@ -0,0 +1,239 @@
|
|||
/* nmcli - command-line tool to control NetworkManager
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright 2010 - 2017 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "nm-default.h"
|
||||
|
||||
#include "nm-client-utils.h"
|
||||
|
||||
/*
|
||||
* Convert string to signed integer.
|
||||
* If required, the resulting number is checked to be in the <min,max> range.
|
||||
*/
|
||||
gboolean
|
||||
nmc_string_to_int_base (const char *str,
|
||||
int base,
|
||||
gboolean range_check,
|
||||
long int min,
|
||||
long int max,
|
||||
long int *value)
|
||||
{
|
||||
char *end;
|
||||
long int tmp;
|
||||
|
||||
errno = 0;
|
||||
tmp = strtol (str, &end, base);
|
||||
if (errno || *end != '\0' || (range_check && (tmp < min || tmp > max))) {
|
||||
return FALSE;
|
||||
}
|
||||
*value = tmp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert string to unsigned integer.
|
||||
* If required, the resulting number is checked to be in the <min,max> range.
|
||||
*/
|
||||
gboolean
|
||||
nmc_string_to_uint_base (const char *str,
|
||||
int base,
|
||||
gboolean range_check,
|
||||
unsigned long int min,
|
||||
unsigned long int max,
|
||||
unsigned long int *value)
|
||||
{
|
||||
char *end;
|
||||
unsigned long int tmp;
|
||||
|
||||
errno = 0;
|
||||
tmp = strtoul (str, &end, base);
|
||||
if (errno || *end != '\0' || (range_check && (tmp < min || tmp > max))) {
|
||||
return FALSE;
|
||||
}
|
||||
*value = tmp;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_string_to_int (const char *str,
|
||||
gboolean range_check,
|
||||
long int min,
|
||||
long int max,
|
||||
long int *value)
|
||||
{
|
||||
return nmc_string_to_int_base (str, 10, range_check, min, max, value);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_string_to_uint (const char *str,
|
||||
gboolean range_check,
|
||||
unsigned long int min,
|
||||
unsigned long int max,
|
||||
unsigned long int *value)
|
||||
{
|
||||
return nmc_string_to_uint_base (str, 10, range_check, min, max, value);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error)
|
||||
{
|
||||
const char *s_true[] = { "true", "yes", "on", NULL };
|
||||
const char *s_false[] = { "false", "no", "off", NULL };
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (g_strcmp0 (str, "o") == 0) {
|
||||
g_set_error (error, 1, 0,
|
||||
/* Translators: the first %s is the partial value entered by
|
||||
* the user, the second %s a list of compatible values.
|
||||
*/
|
||||
_("'%s' is ambiguous (%s)"), str, "on x off");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nmc_string_is_valid (str, s_true, NULL))
|
||||
*val_bool = TRUE;
|
||||
else if (nmc_string_is_valid (str, s_false, NULL))
|
||||
*val_bool = FALSE;
|
||||
else {
|
||||
g_set_error (error, 1, 0,
|
||||
_("'%s' is not valid; use [%s] or [%s]"),
|
||||
str, "true, yes, on", "false, no, off");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nmc_string_to_tristate (const char *str, NMCTriStateValue *val, GError **error)
|
||||
{
|
||||
const char *s_true[] = { "true", "yes", "on", NULL };
|
||||
const char *s_false[] = { "false", "no", "off", NULL };
|
||||
const char *s_unknown[] = { "unknown", NULL };
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (g_strcmp0 (str, "o") == 0) {
|
||||
g_set_error (error, 1, 0,
|
||||
/* Translators: the first %s is the partial value entered by
|
||||
* the user, the second %s a list of compatible values.
|
||||
*/
|
||||
_("'%s' is ambiguous (%s)"), str, "on x off");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nmc_string_is_valid (str, s_true, NULL))
|
||||
*val = NMC_TRI_STATE_YES;
|
||||
else if (nmc_string_is_valid (str, s_false, NULL))
|
||||
*val = NMC_TRI_STATE_NO;
|
||||
else if (nmc_string_is_valid (str, s_unknown, NULL))
|
||||
*val = NMC_TRI_STATE_UNKNOWN;
|
||||
else {
|
||||
g_set_error (error, 1, 0,
|
||||
_("'%s' is not valid; use [%s], [%s] or [%s]"),
|
||||
str, "true, yes, on", "false, no, off", "unknown");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether 'input' is contained in 'allowed' array. It performs case
|
||||
* insensitive comparison and supports shortcut strings if they are unique.
|
||||
* Returns: a pointer to found string in allowed array on success or NULL.
|
||||
* On failure: error->code : 0 - string not found; 1 - string is ambiguous
|
||||
*/
|
||||
const char *
|
||||
nmc_string_is_valid (const char *input, const char **allowed, GError **error)
|
||||
{
|
||||
const char **p;
|
||||
size_t input_ln, p_len;
|
||||
gboolean prev_match = FALSE;
|
||||
const char *ret = NULL;
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
if (!input || !*input)
|
||||
goto finish;
|
||||
|
||||
input_ln = strlen (input);
|
||||
for (p = allowed; p && *p; p++) {
|
||||
p_len = strlen (*p);
|
||||
if (g_ascii_strncasecmp (input, *p, input_ln) == 0) {
|
||||
if (input_ln == p_len) {
|
||||
ret = *p;
|
||||
break;
|
||||
}
|
||||
if (!prev_match)
|
||||
ret = *p;
|
||||
else {
|
||||
g_set_error (error, 1, 1, _("'%s' is ambiguous (%s x %s)"),
|
||||
input, ret, *p);
|
||||
return NULL;
|
||||
}
|
||||
prev_match = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
if (ret == NULL) {
|
||||
char *valid_vals = g_strjoinv (", ", (char **) allowed);
|
||||
if (!input || !*input)
|
||||
g_set_error (error, 1, 0, _("missing name, try one of [%s]"), valid_vals);
|
||||
else
|
||||
g_set_error (error, 1, 0, _("'%s' not among [%s]"), input, valid_vals);
|
||||
|
||||
g_free (valid_vals);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper function for g_strsplit_set() that removes empty strings
|
||||
* from the vector as they are not useful in most cases.
|
||||
*/
|
||||
char **
|
||||
nmc_strsplit_set (const char *str, const char *delimiter, int max_tokens)
|
||||
{
|
||||
char **result;
|
||||
uint i;
|
||||
uint j;
|
||||
|
||||
result = g_strsplit_set (str, delimiter, max_tokens);
|
||||
|
||||
/* remove empty strings */
|
||||
for (i = 0; result && result[i]; i++) {
|
||||
if (*(result[i]) == '\0') {
|
||||
g_free (result[i]);
|
||||
for (j = i; result[j]; j++)
|
||||
result[j] = result[j + 1];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean
|
||||
matches (const char *cmd, const char *pattern)
|
||||
{
|
||||
size_t len = strlen (cmd);
|
||||
if (!len || len > strlen (pattern))
|
||||
return FALSE;
|
||||
return memcmp (pattern, cmd, len) == 0;
|
||||
}
|
||||
|
63
clients/common/nm-client-utils.h
Normal file
63
clients/common/nm-client-utils.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* nmcli - command-line tool to control NetworkManager
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright 2010 - 2017 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __NM_CLIENT_UTILS_H__
|
||||
#define __NM_CLIENT_UTILS_H__
|
||||
|
||||
#include "nm-meta-setting.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
NMC_TRI_STATE_NO,
|
||||
NMC_TRI_STATE_YES,
|
||||
NMC_TRI_STATE_UNKNOWN,
|
||||
} NMCTriStateValue;
|
||||
|
||||
const char *nmc_string_is_valid (const char *input, const char **allowed, GError **error);
|
||||
|
||||
char **nmc_strsplit_set (const char *str, const char *delimiter, int max_tokens);
|
||||
|
||||
gboolean nmc_string_to_int_base (const char *str,
|
||||
int base,
|
||||
gboolean range_check,
|
||||
long int min,
|
||||
long int max,
|
||||
long int *value);
|
||||
gboolean nmc_string_to_uint_base (const char *str,
|
||||
int base,
|
||||
gboolean range_check,
|
||||
unsigned long int min,
|
||||
unsigned long int max,
|
||||
unsigned long int *value);
|
||||
gboolean nmc_string_to_int (const char *str,
|
||||
gboolean range_check,
|
||||
long int min,
|
||||
long int max,
|
||||
long int *value);
|
||||
gboolean nmc_string_to_uint (const char *str,
|
||||
gboolean range_check,
|
||||
unsigned long int min,
|
||||
unsigned long int max,
|
||||
unsigned long int *value);
|
||||
gboolean nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error);
|
||||
gboolean nmc_string_to_tristate (const char *str, NMCTriStateValue *val, GError **error);
|
||||
|
||||
gboolean matches (const char *cmd, const char *pattern);
|
||||
|
||||
#endif /* __NM_CLIENT_UTILS_H__ */
|
|
@ -25,11 +25,27 @@
|
|||
#include <arpa/inet.h>
|
||||
|
||||
#include "nm-common-macros.h"
|
||||
#include "nm-vpn-helpers.h"
|
||||
|
||||
/* FIXME: don't include headers from nmcli */
|
||||
#include "utils.h"
|
||||
#include "common.h"
|
||||
#include "nm-vpn-helpers.h"
|
||||
#include "nm-client-utils.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* FIXME: don't include headers from nmcli. And move all uses of NMClient out
|
||||
* of there. */
|
||||
|
||||
/* FIXME: don't directly print any warnings. Instead, add a hook mechanism to notify
|
||||
* the caller about warnings, error or whatever.
|
||||
*/
|
||||
|
||||
#include "nmcli.h"
|
||||
|
||||
NMConnection *
|
||||
nmc_find_connection (const GPtrArray *connections,
|
||||
const char *filter_type,
|
||||
const char *filter_val,
|
||||
int *start,
|
||||
gboolean complete);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
@ -46,6 +62,428 @@ static char *secret_flags_to_string (guint32 flags, NMMetaAccessorGetType get_ty
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Parse IP address from string to NMIPAddress stucture.
|
||||
* ip_str is the IP address in the form address/prefix
|
||||
*/
|
||||
static NMIPAddress *
|
||||
nmc_parse_and_build_address (int family, const char *ip_str, GError **error)
|
||||
{
|
||||
int max_prefix = (family == AF_INET) ? 32 : 128;
|
||||
NMIPAddress *addr = NULL;
|
||||
const char *ip;
|
||||
char *tmp;
|
||||
char *plen;
|
||||
long int prefix;
|
||||
GError *local = NULL;
|
||||
|
||||
g_return_val_if_fail (ip_str != NULL, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
tmp = g_strdup (ip_str);
|
||||
plen = strchr (tmp, '/'); /* prefix delimiter */
|
||||
if (plen)
|
||||
*plen++ = '\0';
|
||||
|
||||
ip = tmp;
|
||||
|
||||
prefix = max_prefix;
|
||||
if (plen) {
|
||||
if (!nmc_string_to_int (plen, TRUE, 1, max_prefix, &prefix)) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("invalid prefix '%s'; <1-%d> allowed"), plen, max_prefix);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
addr = nm_ip_address_new (family, ip, (guint32) prefix, &local);
|
||||
if (!addr) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("invalid IP address: %s"), local->message);
|
||||
g_clear_error (&local);
|
||||
}
|
||||
|
||||
finish:
|
||||
g_free (tmp);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* nmc_parse_and_build_route:
|
||||
* @family: AF_INET or AF_INET6
|
||||
* @str: route string to be parsed
|
||||
* @error: location to store GError
|
||||
*
|
||||
* Parse route from string and return an #NMIPRoute
|
||||
*
|
||||
* Returns: a new #NMIPRoute or %NULL on error
|
||||
*/
|
||||
static NMIPRoute *
|
||||
nmc_parse_and_build_route (int family,
|
||||
const char *str,
|
||||
GError **error)
|
||||
{
|
||||
int max_prefix = (family == AF_INET) ? 32 : 128;
|
||||
char *plen = NULL;
|
||||
const char *next_hop = NULL;
|
||||
const char *canon_dest;
|
||||
long int prefix = max_prefix;
|
||||
unsigned long int tmp_ulong;
|
||||
NMIPRoute *route = NULL;
|
||||
gboolean success = FALSE;
|
||||
GError *local = NULL;
|
||||
gint64 metric = -1;
|
||||
guint i, len;
|
||||
gs_strfreev char **routev = NULL;
|
||||
gs_free char *value = NULL;
|
||||
gs_free char *dest = NULL;
|
||||
gs_unref_hashtable GHashTable *attrs = NULL;
|
||||
GHashTable *tmp_attrs;
|
||||
|
||||
g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
|
||||
g_return_val_if_fail (str, FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
value = g_strdup (str);
|
||||
routev = nmc_strsplit_set (g_strstrip (value), " \t", 0);
|
||||
len = g_strv_length (routev);
|
||||
if (len < 1) {
|
||||
g_set_error (error, 1, 0, _("'%s' is not valid (the format is: ip[/prefix] [next-hop] [metric] [attr=val] [attr=val])"),
|
||||
str);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
dest = g_strdup (routev[0]);
|
||||
plen = strchr (dest, '/'); /* prefix delimiter */
|
||||
if (plen)
|
||||
*plen++ = '\0';
|
||||
|
||||
if (plen) {
|
||||
if (!nmc_string_to_int (plen, TRUE, 1, max_prefix, &prefix)) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("invalid prefix '%s'; <1-%d> allowed"),
|
||||
plen, max_prefix);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i < len; i++) {
|
||||
if (nm_utils_ipaddr_valid (family, routev[i])) {
|
||||
if (metric != -1 || attrs) {
|
||||
g_set_error (error, 1, 0, _("the next hop ('%s') must be first"), routev[i]);
|
||||
goto finish;
|
||||
}
|
||||
next_hop = routev[i];
|
||||
} else if (nmc_string_to_uint (routev[i], TRUE, 0, G_MAXUINT32, &tmp_ulong)) {
|
||||
if (attrs) {
|
||||
g_set_error (error, 1, 0, _("the metric ('%s') must be before attributes"), routev[i]);
|
||||
goto finish;
|
||||
}
|
||||
metric = tmp_ulong;
|
||||
} else if (strchr (routev[i], '=')) {
|
||||
GHashTableIter iter;
|
||||
char *iter_key;
|
||||
GVariant *iter_value;
|
||||
|
||||
tmp_attrs = nm_utils_parse_variant_attributes (routev[i], ' ', '=', FALSE,
|
||||
nm_ip_route_get_variant_attribute_spec(),
|
||||
error);
|
||||
if (!tmp_attrs) {
|
||||
g_prefix_error (error, "invalid option '%s': ", routev[i]);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!attrs)
|
||||
attrs = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
g_hash_table_iter_init (&iter, tmp_attrs);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &iter_key, (gpointer *) &iter_value)) {
|
||||
if (!nm_ip_route_attribute_validate (iter_key, iter_value, family, NULL, error)) {
|
||||
g_prefix_error (error, "%s: ", iter_key);
|
||||
g_hash_table_unref (tmp_attrs);
|
||||
goto finish;
|
||||
}
|
||||
g_hash_table_insert (attrs, iter_key, iter_value);
|
||||
g_hash_table_iter_steal (&iter);
|
||||
}
|
||||
g_hash_table_unref (tmp_attrs);
|
||||
} else {
|
||||
g_set_error (error, 1, 0, _("unrecognized option '%s'"), routev[i]);
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
route = nm_ip_route_new (family, dest, prefix, next_hop, metric, &local);
|
||||
if (!route) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("invalid route: %s"), local->message);
|
||||
g_clear_error (&local);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* We don't accept default routes as NetworkManager handles it
|
||||
* itself. But we have to check this after @route has normalized the
|
||||
* dest string.
|
||||
*/
|
||||
canon_dest = nm_ip_route_get_dest (route);
|
||||
if (!strcmp (canon_dest, "0.0.0.0") || !strcmp (canon_dest, "::")) {
|
||||
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("default route cannot be added (NetworkManager handles it by itself)"));
|
||||
g_clear_pointer (&route, nm_ip_route_unref);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (attrs) {
|
||||
GHashTableIter iter;
|
||||
char *name;
|
||||
GVariant *variant;
|
||||
|
||||
g_hash_table_iter_init (&iter, attrs);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant))
|
||||
nm_ip_route_set_attribute (route, name, variant);
|
||||
}
|
||||
|
||||
success = TRUE;
|
||||
|
||||
finish:
|
||||
return route;
|
||||
}
|
||||
|
||||
/* Max priority values from libnm-core/nm-setting-vlan.c */
|
||||
#define MAX_SKB_PRIO G_MAXUINT32
|
||||
#define MAX_8021P_PRIO 7 /* Max 802.1p priority */
|
||||
|
||||
/*
|
||||
* Parse VLAN priority mappings from the following format: 2:1,3:4,7:3
|
||||
* and verify if the priority numbers are valid
|
||||
*
|
||||
* Return: string array with split maps, or NULL on error
|
||||
* Caller is responsible for freeing the array.
|
||||
*/
|
||||
static char **
|
||||
nmc_vlan_parse_priority_maps (const char *priority_map,
|
||||
NMVlanPriorityMap map_type,
|
||||
GError **error)
|
||||
{
|
||||
char **mapping = NULL, **iter;
|
||||
unsigned long from, to, from_max, to_max;
|
||||
|
||||
g_return_val_if_fail (priority_map != NULL, NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
if (map_type == NM_VLAN_INGRESS_MAP) {
|
||||
from_max = MAX_8021P_PRIO;
|
||||
to_max = MAX_SKB_PRIO;
|
||||
} else {
|
||||
from_max = MAX_SKB_PRIO;
|
||||
to_max = MAX_8021P_PRIO;
|
||||
}
|
||||
|
||||
mapping = g_strsplit (priority_map, ",", 0);
|
||||
for (iter = mapping; iter && *iter; iter++) {
|
||||
char *left, *right;
|
||||
|
||||
left = g_strstrip (*iter);
|
||||
right = strchr (left, ':');
|
||||
if (!right) {
|
||||
g_set_error (error, 1, 0, _("invalid priority map '%s'"), *iter);
|
||||
g_strfreev (mapping);
|
||||
return NULL;
|
||||
}
|
||||
*right++ = '\0';
|
||||
|
||||
if (!nmc_string_to_uint (left, TRUE, 0, from_max, &from)) {
|
||||
g_set_error (error, 1, 0, _("priority '%s' is not valid (<0-%ld>)"),
|
||||
left, from_max);
|
||||
g_strfreev (mapping);
|
||||
return NULL;
|
||||
}
|
||||
if (!nmc_string_to_uint (right, TRUE, 0, to_max, &to)) {
|
||||
g_set_error (error, 1, 0, _("priority '%s' is not valid (<0-%ld>)"),
|
||||
right, to_max);
|
||||
g_strfreev (mapping);
|
||||
return NULL;
|
||||
}
|
||||
*(right-1) = ':'; /* Put back ':' */
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/*
|
||||
* nmc_proxy_check_script:
|
||||
* @script: file name with PAC script, or raw PAC Script data
|
||||
* @out_script: raw PAC Script (with removed new-line characters)
|
||||
* @error: location to store error, or %NULL
|
||||
*
|
||||
* Check PAC Script from @script parameter and return the checked/sanitized
|
||||
* config in @out_script.
|
||||
*
|
||||
* Returns: %TRUE if the script is valid, %FALSE if it is invalid
|
||||
*/
|
||||
static gboolean
|
||||
nmc_proxy_check_script (const char *script, char **out_script, GError **error)
|
||||
{
|
||||
enum {
|
||||
_PAC_SCRIPT_TYPE_GUESS,
|
||||
_PAC_SCRIPT_TYPE_FILE,
|
||||
_PAC_SCRIPT_TYPE_JSON,
|
||||
} desired_type = _PAC_SCRIPT_TYPE_GUESS;
|
||||
const char *filename = NULL;
|
||||
size_t c_len = 0;
|
||||
gs_free char *script_clone = NULL;
|
||||
|
||||
*out_script = NULL;
|
||||
|
||||
if (!script || !script[0])
|
||||
return TRUE;
|
||||
|
||||
if (g_str_has_prefix (script, "file://")) {
|
||||
script += NM_STRLEN ("file://");
|
||||
desired_type = _PAC_SCRIPT_TYPE_FILE;
|
||||
} else if (g_str_has_prefix (script, "js://")) {
|
||||
script += NM_STRLEN ("js://");
|
||||
desired_type = _PAC_SCRIPT_TYPE_JSON;
|
||||
}
|
||||
|
||||
if (NM_IN_SET (desired_type, _PAC_SCRIPT_TYPE_FILE, _PAC_SCRIPT_TYPE_GUESS)) {
|
||||
gs_free char *contents = NULL;
|
||||
|
||||
if (!g_file_get_contents (script, &contents, &c_len, NULL)) {
|
||||
if (desired_type == _PAC_SCRIPT_TYPE_FILE) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("cannot read pac-script from file '%s'"),
|
||||
script);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (c_len != strlen (contents)) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("file '%s' contains non-valid utf-8"),
|
||||
script);
|
||||
return FALSE;
|
||||
}
|
||||
filename = script;
|
||||
script = script_clone = g_steal_pointer (&contents);
|
||||
}
|
||||
}
|
||||
|
||||
if ( !strstr (script, "FindProxyForURL")
|
||||
|| !g_utf8_validate (script, -1, NULL)) {
|
||||
if (filename) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("'%s' does not contain a valid PAC Script"), filename);
|
||||
} else {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("Not a valid PAC Script"));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*out_script = (script == script_clone)
|
||||
? g_steal_pointer (&script_clone)
|
||||
: g_strdup (script);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const char *
|
||||
nmc_bond_validate_mode (const char *mode, GError **error)
|
||||
{
|
||||
unsigned long mode_int;
|
||||
static const char *valid_modes[] = { "balance-rr",
|
||||
"active-backup",
|
||||
"balance-xor",
|
||||
"broadcast",
|
||||
"802.3ad",
|
||||
"balance-tlb",
|
||||
"balance-alb",
|
||||
NULL };
|
||||
if (nmc_string_to_uint (mode, TRUE, 0, 6, &mode_int)) {
|
||||
/* Translate bonding mode numbers to mode names:
|
||||
* https://www.kernel.org/doc/Documentation/networking/bonding.txt
|
||||
*/
|
||||
return valid_modes[mode_int];
|
||||
} else
|
||||
return nmc_string_is_valid (mode, valid_modes, error);
|
||||
}
|
||||
|
||||
/*
|
||||
* nmc_team_check_config:
|
||||
* @config: file name with team config, or raw team JSON config data
|
||||
* @out_config: raw team JSON config data
|
||||
* The value must be freed with g_free().
|
||||
* @error: location to store error, or %NUL
|
||||
*
|
||||
* Check team config from @config parameter and return the checked
|
||||
* config in @out_config.
|
||||
*
|
||||
* Returns: %TRUE if the config is valid, %FALSE if it is invalid
|
||||
*/
|
||||
static gboolean
|
||||
nmc_team_check_config (const char *config, char **out_config, GError **error)
|
||||
{
|
||||
enum {
|
||||
_TEAM_CONFIG_TYPE_GUESS,
|
||||
_TEAM_CONFIG_TYPE_FILE,
|
||||
_TEAM_CONFIG_TYPE_JSON,
|
||||
} desired_type = _TEAM_CONFIG_TYPE_GUESS;
|
||||
const char *filename = NULL;
|
||||
size_t c_len = 0;
|
||||
gs_free char *config_clone = NULL;
|
||||
|
||||
*out_config = NULL;
|
||||
|
||||
if (!config || !config[0])
|
||||
return TRUE;
|
||||
|
||||
if (g_str_has_prefix (config, "file://")) {
|
||||
config += NM_STRLEN ("file://");
|
||||
desired_type = _TEAM_CONFIG_TYPE_FILE;
|
||||
} else if (g_str_has_prefix (config, "json://")) {
|
||||
config += NM_STRLEN ("json://");
|
||||
desired_type = _TEAM_CONFIG_TYPE_JSON;
|
||||
}
|
||||
|
||||
if (NM_IN_SET (desired_type, _TEAM_CONFIG_TYPE_FILE, _TEAM_CONFIG_TYPE_GUESS)) {
|
||||
gs_free char *contents = NULL;
|
||||
|
||||
if (!g_file_get_contents (config, &contents, &c_len, NULL)) {
|
||||
if (desired_type == _TEAM_CONFIG_TYPE_FILE) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("cannot read team config from file '%s'"),
|
||||
config);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (c_len != strlen (contents)) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("team config file '%s' contains non-valid utf-8"),
|
||||
config);
|
||||
return FALSE;
|
||||
}
|
||||
filename = config;
|
||||
config = config_clone = g_steal_pointer (&contents);
|
||||
}
|
||||
}
|
||||
|
||||
if (!nm_utils_is_json_object (config, NULL)) {
|
||||
if (filename) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("'%s' does not contain a valid team configuration"), filename);
|
||||
} else {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
|
||||
_("team configuration must be a JSON object"));
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*out_config = (config == config_clone)
|
||||
? g_steal_pointer (&config_clone)
|
||||
: g_strdup (config);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define ARGS_DESCRIBE_FCN \
|
||||
const NMMetaSettingInfoEditor *setting_info, const NMMetaPropertyInfo *property_info, char **out_to_free
|
||||
|
||||
|
@ -3933,6 +4371,11 @@ nmc_value_transform_char_string (const GValue *src_value,
|
|||
static void __attribute__((constructor))
|
||||
register_nmcli_value_transforms (void)
|
||||
{
|
||||
/* FIXME: we should not register a g-value transform function. Instead, our meta data
|
||||
* should be able to access the values according to their type.
|
||||
*
|
||||
* Also, running code as a ((constructor)) is hightly unexpected and affects the
|
||||
* entire binary. */
|
||||
g_value_register_transform_func (G_TYPE_BOOLEAN, G_TYPE_STRING, nmc_value_transform_bool_string);
|
||||
g_value_register_transform_func (G_TYPE_CHAR, G_TYPE_STRING, nmc_value_transform_char_string);
|
||||
}
|
||||
|
@ -6106,3 +6549,4 @@ const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[_NM_META_SETTING_TYPE
|
|||
.properties_num = G_N_ELEMENTS (property_infos_wireless_security),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -115,4 +115,7 @@ struct _NMMetaSettingInfoEditor {
|
|||
|
||||
extern const NMMetaSettingInfoEditor nm_meta_setting_infos_editor[_NM_META_SETTING_TYPE_NUM];
|
||||
|
||||
/* FIXME: don't expose this function on it's own, at least not from this file. */
|
||||
const char *nmc_bond_validate_mode (const char *mode, GError **error);
|
||||
|
||||
#endif /* __NM_META_SETTING_DESC_H__ */
|
||||
|
|
|
@ -438,7 +438,7 @@ set_property (GObject *object, guint prop_id,
|
|||
nm_clear_g_free (&priv->keys);
|
||||
return;
|
||||
}
|
||||
g_hash_table_iter_init (&iter, priv->data);
|
||||
g_hash_table_iter_init (&iter, data);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) {
|
||||
if (!nm_setting_user_check_key (key, NULL))
|
||||
g_return_if_reached ();
|
||||
|
|
|
@ -10,6 +10,7 @@ clients/cli/nmcli.c
|
|||
clients/cli/polkit-agent.c
|
||||
clients/cli/settings.c
|
||||
clients/cli/utils.c
|
||||
clients/common/nm-client-utils.c
|
||||
clients/common/nm-meta-setting-desc.c
|
||||
clients/common/nm-polkit-listener.c
|
||||
clients/common/nm-secret-agent-simple.c
|
||||
|
|
|
@ -62,10 +62,12 @@ gint _nm_utils_ascii_str_to_bool (const char *str,
|
|||
* error reason. Depending on the usage, this might indicate a bug because
|
||||
* usually the target object should stay alive as long as there are pending
|
||||
* operations.
|
||||
* @NM_UTILS_ERROR_INVALID_ARGUMENT: invalid argument.
|
||||
*/
|
||||
typedef enum {
|
||||
NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/
|
||||
NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/
|
||||
NM_UTILS_ERROR_INVALID_ARGUMENT, /*< nick=InvalidArgument >*/
|
||||
} NMUtilsError;
|
||||
|
||||
#define NM_UTILS_ERROR (nm_utils_error_quark ())
|
||||
|
|
Loading…
Reference in a new issue