diff --git a/pressure-vessel/runtime.c b/pressure-vessel/runtime.c index 465b39409b7a01e5d00b49812420b11571160d90..d5e80736fb64bdbce8d4c626cce8ee9fb8a1509d 100644 --- a/pressure-vessel/runtime.c +++ b/pressure-vessel/runtime.c @@ -1460,6 +1460,45 @@ icd_details_free (IcdDetails *self) G_DEFINE_AUTOPTR_CLEANUP_FUNC (IcdDetails, icd_details_free) +/* + * @capture_libs: (not nullable): hash table where the keys are the + * destinations and the values are GList of patterns for capsule-capture-libs + */ +static gboolean +bind_icd (PvRuntime *self, + RuntimeArchitecture *arch, + GHashTable *capture_libs, + GError **error) +{ + GHashTableIter iter; + const gchar *dest = NULL; + GList *patterns = NULL; + const GList *l = NULL; + + g_return_val_if_fail (runtime_architecture_check_valid (arch), FALSE); + g_return_val_if_fail (capture_libs != NULL, FALSE); + + if (!pv_runtime_provide_container_access (self, error)) + return FALSE; + + g_hash_table_iter_init (&iter, capture_libs); + while (g_hash_table_iter_next (&iter, (gpointer *)&dest, (gpointer *)&patterns)) + { + g_autoptr(FlatpakBwrap) temp_bwrap = NULL; + temp_bwrap = pv_runtime_get_capsule_capture_libs (self, arch); + flatpak_bwrap_add_args (temp_bwrap, "--dest", dest, NULL); + + for (l = patterns; l != NULL; l = l->next) + flatpak_bwrap_add_arg (temp_bwrap, (gchar *)l->data); + + flatpak_bwrap_finish (temp_bwrap); + + if (!pv_bwrap_run_sync (temp_bwrap, NULL, error)) + return FALSE; + } + return TRUE; +} + /* * @sequence_number: numbered directory to use to disambiguate between * colliding files with the same basename @@ -1470,19 +1509,22 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (IcdDetails, icd_details_free) * @use_subdir_for_soname: if %TRUE, the @requested_subdir will be always * used. If %FALSE, the @requested_subdir will not be used when the provided * library is of the kind "ICD_KIND_SONAME". + * @patterns_table: (inout) (not nullable): hash table where the keys are the + * destinations and the values are GList of patterns for capsule-capture-libs * @search_path: (nullable): Add the parent directory of the resulting * ICD to this search path if necessary */ static gboolean -bind_icd (PvRuntime *self, - RuntimeArchitecture *arch, - gsize sequence_number, - const char *requested_subdir, - IcdDetails *details, - gboolean *use_numbered_subdirs, - gboolean use_subdir_for_kind_soname, - GString *search_path, - GError **error) +get_icd_to_bind (PvRuntime *self, + RuntimeArchitecture *arch, + gsize sequence_number, + const char *requested_subdir, + IcdDetails *details, + gboolean *use_numbered_subdirs, + gboolean use_subdir_for_kind_soname, + GHashTable *patterns_table, + GString *search_path, + GError **error) { static const char options[] = "if-exists:if-same-abi"; g_autofree gchar *in_current_namespace = NULL; @@ -1490,14 +1532,12 @@ bind_icd (PvRuntime *self, g_autofree gchar *dependency_pattern = NULL; g_autofree gchar *seq_str = NULL; g_autofree gchar *final_path = NULL; + g_autofree gchar *org_key = NULL; const char *base; const char *mode; - g_autoptr(FlatpakBwrap) temp_bwrap = NULL; gsize multiarch_index; - g_autoptr(GDir) dir = NULL; - gsize dir_elements_before = 0; - gsize dir_elements_after = 0; const gchar *subdir = requested_subdir; + GList *patterns_in_hashtable = NULL; g_return_val_if_fail (runtime_architecture_check_valid (arch), FALSE); g_return_val_if_fail (subdir != NULL, FALSE); @@ -1509,6 +1549,7 @@ bind_icd (PvRuntime *self, g_return_val_if_fail (details->paths_in_container[multiarch_index] == NULL, FALSE); g_return_val_if_fail (use_numbered_subdirs != NULL, FALSE); + g_return_val_if_fail (patterns_table != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_info ("Capturing loadable module: %s", details->resolved_library); @@ -1571,50 +1612,32 @@ bind_icd (PvRuntime *self, return TRUE; } - dir = g_dir_open (in_current_namespace, 0, error); - if (dir == NULL) - return FALSE; - - /* Number of elements before trying to capture the library */ - while (g_dir_read_name (dir)) - dir_elements_before++; - pattern = g_strdup_printf ("no-dependencies:even-if-older:%s:%s:%s", options, mode, details->resolved_library); dependency_pattern = g_strdup_printf ("only-dependencies:%s:%s:%s", options, mode, details->resolved_library); - if (!pv_runtime_provide_container_access (self, error)) - return FALSE; - - temp_bwrap = pv_runtime_get_capsule_capture_libs (self, arch); - flatpak_bwrap_add_args (temp_bwrap, - "--dest", in_current_namespace, - pattern, - NULL); - flatpak_bwrap_finish (temp_bwrap); - - if (!pv_bwrap_run_sync (temp_bwrap, NULL, error)) - return FALSE; - - g_clear_pointer (&temp_bwrap, flatpak_bwrap_free); - - g_dir_rewind (dir); - while (g_dir_read_name (dir)) - dir_elements_after++; - - if (dir_elements_before == dir_elements_after) - { - /* If we have the same number of elements it means that we didn't - * create a symlink to the ICD itself (it must have been nonexistent - * or for a different ABI). When this happens we set the kinds to - * "NONEXISTENT" and return early without trying to capture the - * dependencies. */ - details->kinds[multiarch_index] = ICD_KIND_NONEXISTENT; - /* If the directory is empty we can also remove it */ - g_rmdir (in_current_namespace); - return TRUE; - } + /* We can't use g_hash_table_steal_extended() because we are targeting an + * older GLib version. + * + * Steal the key and value from the hash table, without freeing them. Then + * we update the list and put it back in the hash table */ + g_hash_table_lookup_extended (patterns_table, in_current_namespace, + (gpointer *)&org_key, (gpointer *)&patterns_in_hashtable); + g_hash_table_steal (patterns_table, in_current_namespace); + patterns_in_hashtable = g_list_prepend (patterns_in_hashtable, g_steal_pointer (&pattern)); + g_hash_table_replace (patterns_table, g_steal_pointer (&in_current_namespace), + patterns_in_hashtable); + g_free (org_key); + patterns_in_hashtable = NULL; + + g_hash_table_lookup_extended (patterns_table, arch->libdir_in_current_namespace, + (gpointer *)&org_key, (gpointer *)&patterns_in_hashtable); + g_hash_table_steal (patterns_table, arch->libdir_in_current_namespace); + patterns_in_hashtable = g_list_prepend (patterns_in_hashtable, + g_steal_pointer (&dependency_pattern)); + g_hash_table_replace (patterns_table, g_strdup (arch->libdir_in_current_namespace), + patterns_in_hashtable); /* Only add the numbered subdirectories to the search path. Their * parent is expected to be there already. */ @@ -1627,21 +1650,8 @@ bind_icd (PvRuntime *self, pv_search_path_append (search_path, in_container); } - temp_bwrap = pv_runtime_get_capsule_capture_libs (self, arch); - flatpak_bwrap_add_args (temp_bwrap, - "--dest", arch->libdir_in_current_namespace, - dependency_pattern, - NULL); - flatpak_bwrap_finish (temp_bwrap); - - if (!pv_bwrap_run_sync (temp_bwrap, NULL, error)) - return FALSE; - - g_clear_pointer (&temp_bwrap, flatpak_bwrap_free); - if (details->kinds[multiarch_index] == ICD_KIND_ABSOLUTE) { - g_assert (in_current_namespace != NULL); details->paths_in_container[multiarch_index] = g_build_filename (arch->libdir_in_container, subdir, seq_str ? seq_str : "", @@ -2713,6 +2723,12 @@ setup_each_json_manifest (PvRuntime *self, return TRUE; } +static void +patterns_list_free (gpointer list) +{ + g_list_free_full (list, g_free); +} + static gboolean collect_vulkan_layers (PvRuntime *self, const GPtrArray *layer_details, @@ -2720,6 +2736,11 @@ collect_vulkan_layers (PvRuntime *self, const gchar *dir_name, GError **error) { + /* (element-type filename GList) */ + g_autoptr(GHashTable) capture_libs = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + patterns_list_free); gsize j; g_return_val_if_fail (dir_name != NULL, FALSE); @@ -2797,12 +2818,15 @@ collect_vulkan_layers (PvRuntime *self, } } - if (!bind_icd (self, arch, j, dir_name, details, - &use_numbered_subdirs, use_subdir_for_kind_soname, - NULL, error)) + if (!get_icd_to_bind (self, arch, j, dir_name, details, + &use_numbered_subdirs, use_subdir_for_kind_soname, + capture_libs, NULL, error)) return FALSE; } + if (!bind_icd (self, arch, capture_libs, error)) + return FALSE; + return TRUE; } @@ -3500,6 +3524,11 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self, g_autoptr(SrtObjectList) va_api_drivers = NULL; gboolean use_numbered_subdirs; gboolean use_subdir_for_kind_soname; + /* (element-type filename GList) */ + g_autoptr(GHashTable) capture_libs = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + patterns_list_free); if (!pv_runtime_get_ld_so (self, arch, &ld_so_in_runtime, error)) return FALSE; @@ -3547,9 +3576,9 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self, details->resolved_library = srt_egl_icd_resolve_library_path (icd); g_assert (details->resolved_library != NULL); - if (!bind_icd (self, arch, j, "glvnd", details, - &use_numbered_subdirs, use_subdir_for_kind_soname, - NULL, error)) + if (!get_icd_to_bind (self, arch, j, "glvnd", details, + &use_numbered_subdirs, use_subdir_for_kind_soname, + capture_libs, NULL, error)) return FALSE; } @@ -3573,9 +3602,9 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self, details->resolved_library = srt_vulkan_icd_resolve_library_path (icd); g_assert (details->resolved_library != NULL); - if (!bind_icd (self, arch, j, "vulkan", details, - &use_numbered_subdirs, use_subdir_for_kind_soname, - NULL, error)) + if (!get_icd_to_bind (self, arch, j, "vulkan", details, + &use_numbered_subdirs, use_subdir_for_kind_soname, + capture_libs, NULL, error)) return FALSE; } @@ -3614,9 +3643,9 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self, * because they can only be located in a single directory, * so by definition we can't have collisions. Anything that * ends up in a numbered subdirectory won't get used. */ - if (!bind_icd (self, arch, j, "vdpau", details, - &use_numbered_subdirs, use_subdir_for_kind_soname, - NULL, error)) + if (!get_icd_to_bind (self, arch, j, "vdpau", details, + &use_numbered_subdirs, use_subdir_for_kind_soname, + capture_libs, NULL, error)) return FALSE; } @@ -3640,9 +3669,9 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self, g_assert (details->resolved_library != NULL); g_assert (g_path_is_absolute (details->resolved_library)); - if (!bind_icd (self, arch, j, "dri", details, - &use_numbered_subdirs, use_subdir_for_kind_soname, - dri_path, error)) + if (!get_icd_to_bind (self, arch, j, "dri", details, + &use_numbered_subdirs, use_subdir_for_kind_soname, + capture_libs, dri_path, error)) return FALSE; } @@ -3666,12 +3695,15 @@ pv_runtime_use_provider_graphics_stack (PvRuntime *self, g_assert (details->resolved_library != NULL); g_assert (g_path_is_absolute (details->resolved_library)); - if (!bind_icd (self, arch, j, "dri", details, - &use_numbered_subdirs, use_subdir_for_kind_soname, - va_api_path, error)) + if (!get_icd_to_bind (self, arch, j, "dri", details, + &use_numbered_subdirs, use_subdir_for_kind_soname, + capture_libs, va_api_path, error)) return FALSE; } + if (!bind_icd (self, arch, capture_libs, error)) + return FALSE; + libc = g_build_filename (arch->libdir_in_current_namespace, "libc.so.6", NULL); /* If we are going to use the provider's libc6 (likely)