
This changes behavior, in that yes|no prompt and answer is no longer localized. For command line arguments, I think it is always wrong for nmcli to behave differently based on the localization. That is, input properties on command line should not be translated. One could make an argument, that in interactive mode that is different and the user can be prompted in the his language. But I think for consistency, it is wrong to ask for localized nmcli input.
248 lines
7.1 KiB
C
248 lines
7.1 KiB
C
/* 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", "1", NULL };
|
|
const char *s_false[] = { "false", "no", "off", "0", 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)
|
|
{
|
|
/* remove empty strings */
|
|
return _nm_utils_strv_cleanup (g_strsplit_set (str, delimiter, max_tokens),
|
|
FALSE, TRUE, FALSE);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|