/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ /* NetworkManager -- Network link manager * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * * (C) Copyright 2016 Red Hat, Inc. */ #include "nm-default.h" #include "nm-shared-utils.h" #include /*****************************************************************************/ /* _nm_utils_ascii_str_to_int64: * * A wrapper for g_ascii_strtoll, that checks whether the whole string * can be successfully converted to a number and is within a given * range. On any error, @fallback will be returned and %errno will be set * to a non-zero value. On success, %errno will be set to zero, check %errno * for errors. Any trailing or leading (ascii) white space is ignored and the * functions is locale independent. * * The function is guaranteed to return a value between @min and @max * (inclusive) or @fallback. Also, the parsing is rather strict, it does * not allow for any unrecognized characters, except leading and trailing * white space. **/ gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback) { gint64 v; char *s = NULL; if (str) { while (g_ascii_isspace (str[0])) str++; } if (!str || !str[0]) { errno = EINVAL; return fallback; } errno = 0; v = g_ascii_strtoll (str, &s, base); if (errno != 0) return fallback; if (s[0] != '\0') { while (g_ascii_isspace (s[0])) s++; if (s[0] != '\0') { errno = EINVAL; return fallback; } } if (v > max || v < min) { errno = ERANGE; return fallback; } return v; } /*****************************************************************************/ gint _nm_utils_ascii_str_to_bool (const char *str, gint default_value) { gsize len; char *s = NULL; if (!str) return default_value; while (str[0] && g_ascii_isspace (str[0])) str++; if (!str[0]) return default_value; len = strlen (str); if (g_ascii_isspace (str[len - 1])) { s = g_strdup (str); g_strchomp (s); str = s; } if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1")) default_value = TRUE; else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0")) default_value = FALSE; if (s) g_free (s); return default_value; } /*****************************************************************************/ G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error) void nm_utils_error_set_cancelled (GError **error, gboolean is_disposing, const char *instance_name) { if (is_disposing) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING, "Disposing %s instance", instance_name && *instance_name ? instance_name : "source"); } else { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Request cancelled"); } } gboolean nm_utils_error_is_cancelled (GError *error, gboolean consider_is_disposing) { if (error) { if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return TRUE; if ( consider_is_disposing && g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) return TRUE; } return FALSE; } /*****************************************************************************/ /** * nm_g_object_set_property: * @object: the target object * @property_name: the property name * @value: the #GValue to set * @error: (allow-none): optional error argument * * A reimplementation of g_object_set_property(), but instead * returning an error instead of logging a warning. All g_object_set*() * versions in glib require you to not pass invalid types or they will * log a g_warning() -- without reporting an error. We don't want that, * so we need to hack error checking around it. * * Returns: whether the value was successfully set. */ gboolean nm_g_object_set_property (GObject *object, const gchar *property_name, const GValue *value, GError **error) { GParamSpec *pspec; nm_auto_unset_gvalue GValue tmp_value = G_VALUE_INIT; GObjectClass *klass; g_return_val_if_fail (G_IS_OBJECT (object), FALSE); g_return_val_if_fail (property_name != NULL, FALSE); g_return_val_if_fail (G_IS_VALUE (value), FALSE); g_return_val_if_fail (!error || !*error, FALSE); /* g_object_class_find_property() does g_param_spec_get_redirect_target(), * where we differ from a plain g_object_set_property(). */ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name); if (!pspec) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, _("object class '%s' has no property named '%s'"), G_OBJECT_TYPE_NAME (object), property_name); return FALSE; } if (!(pspec->flags & G_PARAM_WRITABLE)) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, _("property '%s' of object class '%s' is not writable"), pspec->name, G_OBJECT_TYPE_NAME (object)); return FALSE; } if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY)) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, _("construct property \"%s\" for object '%s' can't be set after construction"), pspec->name, G_OBJECT_TYPE_NAME (object)); return FALSE; } klass = g_type_class_peek (pspec->owner_type); if (klass == NULL) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, _("'%s::%s' is not a valid property name; '%s' is not a GObject subtype"), g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->owner_type)); return FALSE; } /* provide a copy to work from, convert (if necessary) and validate */ g_value_init (&tmp_value, pspec->value_type); if (!g_value_transform (value, &tmp_value)) { g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, _("unable to set property '%s' of type '%s' from value of type '%s'"), pspec->name, g_type_name (pspec->value_type), G_VALUE_TYPE_NAME (value)); return FALSE; } if ( g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION)) { gs_free char *contents = g_strdup_value_contents (value); g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, _("value \"%s\" of type '%s' is invalid or out of range for property '%s' of type '%s'"), contents, G_VALUE_TYPE_NAME (value), pspec->name, g_type_name (pspec->value_type)); return FALSE; } g_object_set_property (object, property_name, &tmp_value); return TRUE; } /*****************************************************************************/