cli: fix handling uint64 connection property "serial.send-delay"

libnm currently has only one GObject property of type uint64:
"serial.send-delay". However, it's broken because uint64 handling
is not implemented.

    $ nmcli connection add type gsm autoconnect no con-name t ifname '*' apn 'xyz' serial.baud 5
    Connection 't' (4c929f17-9fda-41d6-8f90-897f6d46b078) successfully added.

    $ nmcli connection show t
    ...
    ipv6.dhcp-duid:                         --
    ipv6.dhcp-send-hostname:                yes
    ipv6.dhcp-hostname:                     --
    ipv6.token:                             --

    (process:14016): libnmc-CRITICAL **: 14:08:32.591: file clients/common/nm-meta-setting-desc.c: line 811 (_get_fcn_gobject_int): should not be reached
    serial.baud:                            5
    serial.bits:                            8
    serial.parity:                          none
    serial.stopbits:                        1
    serial.send-delay:                      --
    gsm.number:                             *99#
    ...

    $ nmcli connection add type gsm autoconnect no con-name t ifname '*' apn 'xyz' serial.baud 5 serial.send-delay 100

    (process:14852): libnmc-CRITICAL **: 14:12:24.259: file clients/common/nm-meta-setting-desc.c: line 1131 (_set_fcn_gobject_int): should not be reached
    Segmentation fault (core dumped)

Fixes: b6d9bdcee8
(cherry picked from commit a600b3a3b2)
(cherry picked from commit 1b987a5366)
This commit is contained in:
Thomas Haller 2018-10-16 14:06:43 +02:00
parent 8cb0a13a5b
commit cf482ae8ee
2 changed files with 104 additions and 60 deletions

View file

@ -783,7 +783,8 @@ _get_fcn_gobject_int (ARGS_GET_FCN)
{ {
GParamSpec *pspec; GParamSpec *pspec;
nm_auto_unset_gvalue GValue gval = G_VALUE_INIT; nm_auto_unset_gvalue GValue gval = G_VALUE_INIT;
gint64 v; gboolean is_uint64 = FALSE;
NMMetaSignUnsignInt64 v;
guint base = 10; guint base = 10;
const NMMetaUtilsIntValueInfo *value_infos; const NMMetaUtilsIntValueInfo *value_infos;
char *return_str; char *return_str;
@ -799,13 +800,18 @@ _get_fcn_gobject_int (ARGS_GET_FCN)
NM_SET_OUT (out_is_default, g_param_value_defaults (pspec, &gval)); NM_SET_OUT (out_is_default, g_param_value_defaults (pspec, &gval));
switch (pspec->value_type) { switch (pspec->value_type) {
case G_TYPE_INT: case G_TYPE_INT:
v = g_value_get_int (&gval); v.i64 = g_value_get_int (&gval);
break; break;
case G_TYPE_UINT: case G_TYPE_UINT:
v = g_value_get_uint (&gval); v.u64 = g_value_get_uint (&gval);
is_uint64 = TRUE;
break; break;
case G_TYPE_INT64: case G_TYPE_INT64:
v = g_value_get_int64 (&gval); v.i64 = g_value_get_int64 (&gval);
break;
case G_TYPE_UINT64:
v.u64 = g_value_get_uint64 (&gval);
is_uint64 = TRUE;
break; break;
default: default:
g_return_val_if_reached (NULL); g_return_val_if_reached (NULL);
@ -819,10 +825,16 @@ _get_fcn_gobject_int (ARGS_GET_FCN)
switch (base) { switch (base) {
case 10: case 10:
return_str = g_strdup_printf ("%"G_GINT64_FORMAT, v); if (is_uint64)
return_str = g_strdup_printf ("%"G_GUINT64_FORMAT, v.u64);
else
return_str = g_strdup_printf ("%"G_GINT64_FORMAT, v.i64);
break; break;
case 16: case 16:
return_str = g_strdup_printf ("0x%"G_GINT64_MODIFIER"x", v); if (is_uint64)
return_str = g_strdup_printf ("0x%"G_GINT64_MODIFIER"x", v.u64);
else
return_str = g_strdup_printf ("0x%"G_GINT64_MODIFIER"x", (guint64) v.i64);
break; break;
default: default:
return_str = NULL; return_str = NULL;
@ -833,7 +845,8 @@ _get_fcn_gobject_int (ARGS_GET_FCN)
&& property_info->property_typ_data && property_info->property_typ_data
&& (value_infos = property_info->property_typ_data->subtype.gobject_int.value_infos)) { && (value_infos = property_info->property_typ_data->subtype.gobject_int.value_infos)) {
for (; value_infos->nick; value_infos++) { for (; value_infos->nick; value_infos++) {
if (value_infos->value == v) { if ( ( is_uint64 && value_infos->value.u64 == v.u64)
|| (!is_uint64 && value_infos->value.i64 == v.i64)) {
char *old_str = return_str; char *old_str = return_str;
return_str = g_strdup_printf ("%s (%s)", old_str, value_infos->nick); return_str = g_strdup_printf ("%s (%s)", old_str, value_infos->nick);
@ -1060,16 +1073,21 @@ _set_fcn_gobject_int (ARGS_SET_FCN)
int errsv; int errsv;
const GParamSpec *pspec; const GParamSpec *pspec;
nm_auto_unset_gvalue GValue gval = G_VALUE_INIT; nm_auto_unset_gvalue GValue gval = G_VALUE_INIT;
gint64 v = 0; gboolean is_uint64;
NMMetaSignUnsignInt64 v;
gboolean has_minmax = FALSE; gboolean has_minmax = FALSE;
gint64 min = G_MININT64; NMMetaSignUnsignInt64 min = { 0 };
gint64 max = G_MAXINT64; NMMetaSignUnsignInt64 max = { 0 };
guint base = 10; guint base = 10;
const NMMetaUtilsIntValueInfo *value_infos = NULL; const NMMetaUtilsIntValueInfo *value_infos;
gboolean has_value = FALSE;
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), property_info->property_name);
if (!G_IS_PARAM_SPEC (pspec))
g_return_val_if_reached (FALSE);
is_uint64 = NM_IN_SET (pspec->value_type, G_TYPE_UINT, G_TYPE_UINT64);
if (property_info->property_typ_data) { if (property_info->property_typ_data) {
if ( value if ( value
&& (value_infos = property_info->property_typ_data->subtype.gobject_int.value_infos)) { && (value_infos = property_info->property_typ_data->subtype.gobject_int.value_infos)) {
gs_free char *vv_stripped = NULL; gs_free char *vv_stripped = NULL;
@ -1083,85 +1101,106 @@ _set_fcn_gobject_int (ARGS_SET_FCN)
for (; value_infos->nick; value_infos++) { for (; value_infos->nick; value_infos++) {
if (nm_streq (value_infos->nick, vv)) { if (nm_streq (value_infos->nick, vv)) {
v = value_infos->value; v = value_infos->value;
has_value = TRUE; goto have_value_from_nick;
break;
} }
} }
} }
if (property_info->property_typ_data->subtype.gobject_int.base > 0) if (property_info->property_typ_data->subtype.gobject_int.base > 0)
base = property_info->property_typ_data->subtype.gobject_int.base; base = property_info->property_typ_data->subtype.gobject_int.base;
if ( property_info->property_typ_data->subtype.gobject_int.min
|| property_info->property_typ_data->subtype.gobject_int.max) { if ( ( is_uint64
&& ( property_info->property_typ_data->subtype.gobject_int.min.u64
|| property_info->property_typ_data->subtype.gobject_int.max.u64))
|| ( !is_uint64
&& ( property_info->property_typ_data->subtype.gobject_int.min.i64
|| property_info->property_typ_data->subtype.gobject_int.max.i64))) {
min = property_info->property_typ_data->subtype.gobject_int.min; min = property_info->property_typ_data->subtype.gobject_int.min;
max = property_info->property_typ_data->subtype.gobject_int.max; max = property_info->property_typ_data->subtype.gobject_int.max;
has_minmax = TRUE; has_minmax = TRUE;
} }
} }
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (G_OBJECT (setting)), property_info->property_name); if (!has_minmax) {
if (!G_IS_PARAM_SPEC (pspec)) switch (pspec->value_type) {
g_return_val_if_reached (FALSE); case G_TYPE_INT:
switch (pspec->value_type) { {
case G_TYPE_INT: const GParamSpecInt *p = (GParamSpecInt *) pspec;
if (!has_minmax) {
const GParamSpecInt *p = (GParamSpecInt *) pspec;
min = p->minimum; min.i64 = p->minimum;
max = p->maximum; max.i64 = p->maximum;
} }
break; break;
case G_TYPE_UINT: case G_TYPE_UINT:
if (!has_minmax) { {
const GParamSpecUInt *p = (GParamSpecUInt *) pspec; const GParamSpecUInt *p = (GParamSpecUInt *) pspec;
min = p->minimum; min.u64 = p->minimum;
max = p->maximum; max.u64 = p->maximum;
} }
break; break;
case G_TYPE_INT64: case G_TYPE_INT64:
if (!has_minmax) { {
const GParamSpecInt64 *p = (GParamSpecInt64 *) pspec; const GParamSpecInt64 *p = (GParamSpecInt64 *) pspec;
min = p->minimum; min.i64 = p->minimum;
max = p->maximum; max.i64 = p->maximum;
}
break;
case G_TYPE_UINT64:
{
const GParamSpecUInt64 *p = (GParamSpecUInt64 *) pspec;
min.u64 = p->minimum;
max.u64 = p->maximum;
}
break;
default:
g_return_val_if_reached (FALSE);
} }
break;
default:
g_return_val_if_reached (FALSE);
} }
if (!has_value) { if (is_uint64)
v = _nm_utils_ascii_str_to_int64 (value, base, min, max, 0); v.u64 = _nm_utils_ascii_str_to_uint64 (value, base, min.u64, max.u64, 0);
else
v.i64 = _nm_utils_ascii_str_to_int64 (value, base, min.i64, max.i64, 0);
if ((errsv = errno) != 0) { if ((errsv = errno) != 0) {
if (errsv == ERANGE) { if (errsv == ERANGE) {
if (is_uint64) {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("'%s' is out of range [%lli, %lli]"), _("'%s' is out of range [%"G_GUINT64_FORMAT", %"G_GUINT64_FORMAT"]"),
value, value, min.u64, max.u64);
(long long) min,
(long long) max);
} else { } else {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT, g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("'%s' is not a valid number"), value); _("'%s' is out of range [%"G_GINT64_FORMAT", %"G_GINT64_FORMAT"]"),
value, min.i64, max.i64);
} }
return FALSE; } else {
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_INVALID_ARGUMENT,
_("'%s' is not a valid number"), value);
} }
return FALSE;
} }
have_value_from_nick:
g_value_init (&gval, pspec->value_type); g_value_init (&gval, pspec->value_type);
switch (pspec->value_type) { switch (pspec->value_type) {
case G_TYPE_INT: case G_TYPE_INT:
g_value_set_int (&gval, v); g_value_set_int (&gval, v.i64);
break; break;
case G_TYPE_UINT: case G_TYPE_UINT:
g_value_set_uint (&gval, v); g_value_set_uint (&gval, v.u64);
break; break;
case G_TYPE_INT64: case G_TYPE_INT64:
g_value_set_int64 (&gval, v); g_value_set_int64 (&gval, v.i64);
break;
case G_TYPE_UINT64:
g_value_set_uint64 (&gval, v.u64);
break; break;
default: default:
nm_assert_not_reached (); g_return_val_if_reached (FALSE);
break; break;
} }

View file

@ -225,9 +225,14 @@ struct _NMMetaPropertyType {
struct _NMUtilsEnumValueInfo; struct _NMUtilsEnumValueInfo;
typedef union {
gint64 i64;
guint64 u64;
} NMMetaSignUnsignInt64;
typedef struct { typedef struct {
const char *nick; const char *nick;
gint64 value; NMMetaSignUnsignInt64 value;
} NMMetaUtilsIntValueInfo; } NMMetaUtilsIntValueInfo;
struct _NMMetaPropertyTypData { struct _NMMetaPropertyTypData {
@ -248,8 +253,8 @@ struct _NMMetaPropertyTypData {
int value); int value);
} gobject_enum; } gobject_enum;
struct { struct {
gint64 min; NMMetaSignUnsignInt64 min;
gint64 max; NMMetaSignUnsignInt64 max;
guint base; guint base;
const NMMetaUtilsIntValueInfo *value_infos; const NMMetaUtilsIntValueInfo *value_infos;
} gobject_int; } gobject_int;