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:
Thomas Haller 2017-03-28 12:16:31 +02:00
parent b5c8622ad3
commit 23298bfc88
17 changed files with 780 additions and 688 deletions

View file

@ -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 \
\

View file

@ -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

View file

@ -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,

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"
/*****************************************************************************/

View file

@ -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.
*/

View file

@ -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);

View 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;
}

View 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__ */

View file

@ -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),
},
};

View file

@ -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__ */

View file

@ -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 ();

View file

@ -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

View file

@ -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 ())