libnm: add function nm_utils_file_search_in_paths()
authorThomas Haller <thaller@redhat.com>
Tue, 25 Nov 2014 22:01:55 +0000 (23:01 +0100)
committerThomas Haller <thaller@redhat.com>
Fri, 5 Dec 2014 10:07:42 +0000 (11:07 +0100)
We now also use a similar function in VPN plugins. It makes
sense to provide a generic implementation in libnm.

Signed-off-by: Thomas Haller <thaller@redhat.com>
https://bugzilla.gnome.org/show_bug.cgi?id=740783

libnm-core/nm-utils.c
libnm-core/nm-utils.h
libnm-util/libnm-util.ver
libnm-util/nm-utils.c
libnm-util/nm-utils.h
libnm/libnm.ver
po/POTFILES.in

index 835937d..e4a4ab2 100644 (file)
@@ -28,6 +28,7 @@
 #include <uuid/uuid.h>
 #include <libintl.h>
 #include <gmodule.h>
+#include <glib/gi18n-lib.h>
 
 #include "nm-utils.h"
 #include "nm-utils-private.h"
@@ -2193,6 +2194,82 @@ nm_utils_file_is_pkcs12 (const char *filename)
        return crypto_is_pkcs12_file (filename, NULL);
 }
 
+/**********************************************************************************************/
+
+/**
+ * nm_utils_file_search_in_paths:
+ * @progname: the helper program name, like "iptables"
+ *   Must be a non-empty string, without path separator (/).
+ * @try_first: (allow-none): a custom path to try first before searching.
+ *   It is silently ignored if it is empty or not an absolute path.
+ * @paths: (allow-none): a %NULL terminated list of search paths.
+ *   Can be empty or %NULL, in which case only @try_first is checked.
+ * @file_test_flags: the flags passed to g_file_test() when searching
+ *   for @progname. Set it to 0 to skip the g_file_test().
+ * @predicate: if given, pass the file name to this function
+ *   for additional checks. This check is performed after the check for
+ *   @file_test_flags. You cannot omit both @file_test_flags and @predicate.
+ * @user_data: (allow-none): user data for @predicate function.
+ * @error: on failure, a "not found" error using @error_domain and @error_code
+ *
+ * Searches for a @progname file in a list of search @paths.
+ *
+ * Returns: (transfer none): the full path to the helper, if found, or %NULL if not found.
+ *   The returned string is not owned by the caller, but later
+ *   invocations of the function might overwrite it.
+ */
+const char *
+nm_utils_file_search_in_paths (const char *progname,
+                               const char *try_first,
+                               const char *const *paths,
+                               GFileTest file_test_flags,
+                               NMUtilsFileSearchInPathsPredicate predicate,
+                               gpointer user_data,
+                               GError **error)
+{
+       GString *tmp;
+       const char *ret;
+
+       g_return_val_if_fail (!error || !*error, NULL);
+       g_return_val_if_fail (progname && progname[0] && !strchr (progname, '/'), NULL);
+       g_return_val_if_fail (!file_test_flags || predicate, NULL);
+
+       /* Only consider @try_first if it is a valid, absolute path. This makes
+        * it simpler to pass in a path from configure checks. */
+       if (   try_first
+           && try_first[0] == '/'
+           && (file_test_flags == 0 || g_file_test (try_first, file_test_flags))
+           && (!predicate || predicate (try_first, user_data)))
+               return g_intern_string (try_first);
+
+       if (!paths || !*paths)
+               goto NOT_FOUND;
+
+       tmp = g_string_sized_new (50);
+       for (; *paths; paths++) {
+               if (!*paths)
+                       continue;
+               g_string_append (tmp, *paths);
+               if (tmp->str[tmp->len - 1] != '/')
+                       g_string_append_c (tmp, '/');
+               g_string_append (tmp, progname);
+               if (   (file_test_flags == 0 || g_file_test (tmp->str, file_test_flags))
+                   && (!predicate || predicate (tmp->str, user_data))) {
+                       ret = g_intern_string (tmp->str);
+                       g_string_free (tmp, TRUE);
+                       return ret;
+               }
+               g_string_set_size (tmp, 0);
+       }
+       g_string_free (tmp, TRUE);
+
+NOT_FOUND:
+       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Could not find \"%s\" binary"), progname);
+       return NULL;
+}
+
+/**********************************************************************************************/
+
 /* Band, channel/frequency stuff for wireless */
 struct cf_pair {
        guint32 chan;
index a9ecd5e..8c22cfd 100644 (file)
@@ -126,6 +126,16 @@ gboolean nm_utils_file_is_certificate (const char *filename);
 gboolean nm_utils_file_is_private_key (const char *filename, gboolean *out_encrypted);
 gboolean nm_utils_file_is_pkcs12 (const char *filename);
 
+typedef gboolean (*NMUtilsFileSearchInPathsPredicate) (const char *filename, gpointer user_data);
+
+const char *nm_utils_file_search_in_paths (const char *progname,
+                                           const char *try_first,
+                                           const char *const *paths,
+                                           GFileTest file_test_flags,
+                                           NMUtilsFileSearchInPathsPredicate predicate,
+                                           gpointer user_data,
+                                           GError **error);
+
 guint32 nm_utils_wifi_freq_to_channel (guint32 freq);
 guint32 nm_utils_wifi_channel_to_freq (guint32 channel, const char *band);
 guint32 nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band);
index 794cc87..9d78e50 100644 (file)
@@ -612,6 +612,7 @@ global:
        nm_utils_deinit;
        nm_utils_escape_ssid;
        nm_utils_file_is_pkcs12;
+       nm_utils_file_search_in_paths;
        nm_utils_get_private;
        nm_utils_gvalue_hash_dup;
        nm_utils_hex2byte;
index cde2997..5a9caf3 100644 (file)
@@ -28,6 +28,8 @@
 #include <uuid/uuid.h>
 #include <libintl.h>
 #include <gmodule.h>
+#include <gio/gio.h>
+#include <glib/gi18n-lib.h>
 
 #include "nm-utils.h"
 #include "nm-utils-private.h"
@@ -1732,6 +1734,82 @@ nm_utils_file_is_pkcs12 (const char *filename)
        return crypto_is_pkcs12_file (filename, NULL);
 }
 
+/**********************************************************************************************/
+
+/**
+ * nm_utils_file_search_in_paths:
+ * @progname: the helper program name, like "iptables"
+ *   Must be a non-empty string, without path separator (/).
+ * @try_first: (allow-none): a custom path to try first before searching.
+ *   It is silently ignored if it is empty or not an absolute path.
+ * @paths: (allow-none): a %NULL terminated list of search paths.
+ *   Can be empty or %NULL, in which case only @try_first is checked.
+ * @file_test_flags: the flags passed to g_file_test() when searching
+ *   for @progname. Set it to 0 to skip the g_file_test().
+ * @predicate: if given, pass the file name to this function
+ *   for additional checks. This check is performed after the check for
+ *   @file_test_flags. You cannot omit both @file_test_flags and @predicate.
+ * @user_data: (allow-none): user data for @predicate function.
+ * @error: on failure, a "not found" error using @error_domain and @error_code
+ *
+ * Searches for a @progname file in a list of search @paths.
+ *
+ * Returns: (transfer none): the full path to the helper, if found, or %NULL if not found.
+ *   The returned string is not owned by the caller, but later
+ *   invocations of the function might overwrite it.
+ */
+const char *
+nm_utils_file_search_in_paths (const char *progname,
+                               const char *try_first,
+                               const char *const *paths,
+                               GFileTest file_test_flags,
+                               NMUtilsFileSearchInPathsPredicate predicate,
+                               gpointer user_data,
+                               GError **error)
+{
+       GString *tmp;
+       const char *ret;
+
+       g_return_val_if_fail (!error || !*error, NULL);
+       g_return_val_if_fail (progname && progname[0] && !strchr (progname, '/'), NULL);
+       g_return_val_if_fail (!file_test_flags || predicate, NULL);
+
+       /* Only consider @try_first if it is a valid, absolute path. This makes
+        * it simpler to pass in a path from configure checks. */
+       if (   try_first
+           && try_first[0] == '/'
+           && (file_test_flags == 0 || g_file_test (try_first, file_test_flags))
+           && (!predicate || predicate (try_first, user_data)))
+               return g_intern_string (try_first);
+
+       if (!paths || !*paths)
+               goto NOT_FOUND;
+
+       tmp = g_string_sized_new (50);
+       for (; *paths; paths++) {
+               if (!*paths)
+                       continue;
+               g_string_append (tmp, *paths);
+               if (tmp->str[tmp->len - 1] != '/')
+                       g_string_append_c (tmp, '/');
+               g_string_append (tmp, progname);
+               if (   (file_test_flags == 0 || g_file_test (tmp->str, file_test_flags))
+                   && (!predicate || predicate (tmp->str, user_data))) {
+                       ret = g_intern_string (tmp->str);
+                       g_string_free (tmp, TRUE);
+                       return ret;
+               }
+               g_string_set_size (tmp, 0);
+       }
+       g_string_free (tmp, TRUE);
+
+NOT_FOUND:
+       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Could not find \"%s\" binary"), progname);
+       return NULL;
+}
+
+/**********************************************************************************************/
+
 /* Band, channel/frequency stuff for wireless */
 struct cf_pair {
        guint32 chan;
index 896b3e9..530fe83 100644 (file)
@@ -121,6 +121,16 @@ GByteArray *nm_utils_rsa_key_encrypt_aes (const GByteArray *data,
                                           GError **error);
 gboolean nm_utils_file_is_pkcs12 (const char *filename);
 
+typedef gboolean (*NMUtilsFileSearchInPathsPredicate) (const char *filename, gpointer user_data);
+
+const char *nm_utils_file_search_in_paths (const char *progname,
+                                           const char *try_first,
+                                           const char *const *paths,
+                                           GFileTest file_test_flags,
+                                           NMUtilsFileSearchInPathsPredicate predicate,
+                                           gpointer user_data,
+                                           GError **error);
+
 guint32 nm_utils_wifi_freq_to_channel (guint32 freq);
 guint32 nm_utils_wifi_channel_to_freq (guint32 channel, const char *band);
 guint32 nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band);
index d89e478..d56a411 100644 (file)
@@ -759,6 +759,7 @@ global:
        nm_utils_file_is_certificate;
        nm_utils_file_is_pkcs12;
        nm_utils_file_is_private_key;
+       nm_utils_file_search_in_paths;
        nm_utils_hexstr2bin;
        nm_utils_hwaddr_atoba;
        nm_utils_hwaddr_aton;
index 1bc1ccb..926dd6c 100644 (file)
@@ -73,6 +73,7 @@ libnm-core/nm-setting-wired.c
 libnm-core/nm-setting-wireless-security.c
 libnm-core/nm-setting-wireless.c
 libnm-core/nm-setting.c
+libnm-core/nm-utils.c
 libnm-glib/nm-device.c
 libnm-glib/nm-remote-connection.c
 libnm-util/crypto.c