/ libpkg / pkg_abi.c
pkg_abi.c
  1  /*-
  2   * Copyright (c) 2011-2025 Baptiste Daroussin <bapt@FreeBSD.org>
  3   * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
  4   * Copyright (c) 2024 The FreeBSD Foundation
  5   *
  6   * This software was developed in part by Isaac Freund <ifreund@freebsdfoundation.org>
  7   * under sponsorship from the FreeBSD Foundation.
  8   *
  9   * SPDX-License-Identifier: BSD-2-Clause
 10   */
 11  #ifdef HAVE_CONFIG_H
 12  #include "pkg_config.h"
 13  #endif
 14  
 15  #include <ctype.h>
 16  #include <paths.h>
 17  #include <string.h>
 18  #include <unistd.h>
 19  
 20  #include "pkg.h"
 21  #include "private/pkg_abi.h"
 22  #include "private/binfmt.h"
 23  #include "private/event.h"
 24  #include "private/pkg.h"
 25  #include "private/utils.h"
 26  #include "xmalloc.h"
 27  
 28  #define _PATH_UNAME "/usr/bin/uname"
 29  
 30  /* All possibilities on FreeBSD as of 5/26/2014 */
 31  struct arch_trans {
 32  	const char *elftype;
 33  	const char *archid;
 34  };
 35  
 36  static const struct arch_trans machine_arch_translation[] = { { "x86:32", "i386" },
 37  	{ "x86:64", "amd64" }, { "powerpc:32:eb", "powerpc" },
 38  	{ "powerpc:64:eb", "powerpc64" }, { "powerpc:64:el", "powerpc64le" },
 39  	{ "sparc64:64", "sparc64" }, { "ia64:64", "ia64" },
 40  	/* All the ARM stuff */
 41  	{ "armv6:32:el:eabi:hardfp", "armv6" },
 42  	{ "armv7:32:el:eabi:hardfp", "armv7" }, { "aarch64:64", "aarch64" },
 43  	/* And now MIPS */
 44  	{ "mips:32:el:o32", "mipsel" }, { "mips:32:el:n32", "mipsn32el" },
 45  	{ "mips:32:eb:o32", "mips" }, { "mips:32:eb:n32", "mipsn32" },
 46  	{ "mips:64:el:n64", "mips64el" }, { "mips:64:eb:n64", "mips64" },
 47  	/* And RISC-V */
 48  	{ "riscv:32:hf", "riscv32" }, { "riscv:32:sf", "riscv32sf" },
 49  	{ "riscv:64:hf", "riscv64" }, { "riscv:64:sf", "riscv64sf" },
 50  
 51  	{ NULL, NULL } };
 52  
 53  static const struct {
 54  	enum pkg_os os;
 55  	const char *string;
 56  } os_string_table[] = {
 57  	{ PKG_OS_UNKNOWN, "Unknown" },
 58  	{ PKG_OS_FREEBSD, "FreeBSD" },
 59  	{ PKG_OS_NETBSD, "NetBSD" },
 60  	{ PKG_OS_DRAGONFLY, "dragonfly" },
 61  	{ PKG_OS_LINUX, "Linux" },
 62  	{ PKG_OS_DARWIN, "Darwin" },
 63  	{ PKG_OS_ANY, "*" },
 64  	{ -1, NULL },
 65  };
 66  
 67  /* This table does not include PKG_ARCH_AMD64 as the string translation of
 68     that arch is os-dependent. */
 69  static const struct {
 70  	enum pkg_arch arch;
 71  	const char *string;
 72  } arch_string_table[] = {
 73  	{ PKG_ARCH_UNKNOWN, "unknown"},
 74  	{ PKG_ARCH_I386, "i386"},
 75  	{ PKG_ARCH_ARMV6, "armv6"},
 76  	{ PKG_ARCH_ARMV7, "armv7"},
 77  	{ PKG_ARCH_AARCH64, "aarch64"},
 78  	{ PKG_ARCH_POWERPC, "powerpc"},
 79  	{ PKG_ARCH_POWERPC64, "powerpc64"},
 80  	{ PKG_ARCH_POWERPC64LE, "powerpc64le"},
 81  	{ PKG_ARCH_RISCV32, "riscv32"},
 82  	{ PKG_ARCH_RISCV64, "riscv64"},
 83  	{ PKG_ARCH_ANY,	"*"},
 84  	{ -1, NULL },
 85  };
 86  
 87  const char *
 88  pkg_os_to_string(enum pkg_os os)
 89  {
 90  	for (size_t i = 0; os_string_table[i].string != NULL; i++) {
 91  		if (os == os_string_table[i].os) {
 92  			return os_string_table[i].string;
 93  		}
 94  	}
 95  	assert(0);
 96  }
 97  
 98  static enum pkg_os
 99  pkg_os_from_string(const char *string)
100  {
101  	for (size_t i = 0; os_string_table[i].string != NULL; i++) {
102  		if (STREQ(string, os_string_table[i].string)) {
103  			return os_string_table[i].os;
104  		}
105  	}
106  	return (PKG_OS_UNKNOWN);
107  }
108  
109  /* Returns true if the OS uses "amd64" rather than "x86_64" */
110  static bool
111  pkg_os_uses_amd64_name(enum pkg_os os)
112  {
113  	switch (os) {
114  	case PKG_OS_FREEBSD:
115  		return (true);
116  	case PKG_OS_DARWIN:
117  	case PKG_OS_NETBSD:
118  	case PKG_OS_LINUX:
119  		return (false);
120  	case PKG_OS_DRAGONFLY:
121  	case PKG_OS_UNKNOWN:
122  	default:
123  		assert(0);
124  	}
125  }
126  
127  const char *
128  pkg_arch_to_string(enum pkg_os os, enum pkg_arch arch)
129  {
130  	if (arch == PKG_ARCH_AMD64) {
131  		if (os == PKG_OS_DRAGONFLY) {
132  			return ("x86:64");
133  		} else if (pkg_os_uses_amd64_name(os)) {
134  			return ("amd64");
135  		} else {
136  			return ("x86_64");
137  		}
138  	}
139  
140  	for (size_t i = 0; arch_string_table[i].string != NULL; i++) {
141  		if (arch == arch_string_table[i].arch) {
142  			return arch_string_table[i].string;
143  		}
144  	}
145  
146  	assert(0);
147  }
148  
149  static enum pkg_arch
150  pkg_arch_from_string(enum pkg_os os, const char *string)
151  {
152  	if (os == PKG_OS_DRAGONFLY) {
153  		if (STREQ(string, "x86:64")) {
154  			return (PKG_ARCH_AMD64);
155  		}
156  	} else if (pkg_os_uses_amd64_name(os)) {
157  		if (STREQ(string, "amd64")) {
158  			return (PKG_ARCH_AMD64);
159  		}
160  	} else {
161  		if (STREQ(string, "x86_64")) {
162  			return (PKG_ARCH_AMD64);
163  		}
164  	}
165  
166  	for (size_t i = 0; arch_string_table[i].string != NULL; i++) {
167  		if (STREQ(string, arch_string_table[i].string)) {
168  			return arch_string_table[i].arch;
169  		}
170  	}
171  
172  	return (PKG_ARCH_UNKNOWN);
173  }
174  
175  bool
176  pkg_abi_string_only_major_version(enum pkg_os os)
177  {
178  	switch (os) {
179  	case PKG_OS_FREEBSD:
180  	case PKG_OS_NETBSD:
181  	case PKG_OS_DARWIN:
182  		return (true);
183  	case PKG_OS_DRAGONFLY:
184  	case PKG_OS_LINUX:
185  		return (false);
186  	case PKG_OS_UNKNOWN:
187  	default:
188  		assert (0);
189  	}
190  }
191  
192  char *
193  pkg_abi_to_string(const struct pkg_abi *abi)
194  {
195  	char *ret;
196  	if (pkg_abi_string_only_major_version(abi->os)) {
197  		xasprintf(&ret, "%s:%d:%s", pkg_os_to_string(abi->os),
198  		    abi->major, pkg_arch_to_string(abi->os, abi->arch));
199  	} else {
200  		xasprintf(&ret, "%s:%d.%d:%s", pkg_os_to_string(abi->os),
201  		    abi->major, abi->minor,
202  		    pkg_arch_to_string(abi->os, abi->arch));
203  	}
204  	return (ret);
205  }
206  
207  bool
208  pkg_abi_from_string(struct pkg_abi *abi, const char *string)
209  {
210  	*abi = (struct pkg_abi){0};
211  
212  	bool ret = false;
213  
214  	char *copy = xstrdup(string);
215  
216  	char *iter = copy;
217  	char *os = strsep(&iter, ":");
218  	assert(os != NULL);
219  	abi->os = pkg_os_from_string(os);
220  	if (abi->os == PKG_OS_UNKNOWN) {
221  		pkg_emit_error("Unknown OS '%s' in ABI string", os);
222  		goto out;
223  	}
224  
225  	char *version = strsep(&iter, ":");
226  	if (version == NULL) {
227  		if (abi->os == PKG_OS_ANY) {
228  			abi->major = 0;
229  			abi->minor = 0;
230  			abi->arch = PKG_ARCH_ANY;
231  			ret = true;
232  			goto out;
233  		}
234  		pkg_emit_error("Invalid ABI string '%s', "
235  		    "missing version and architecture", string);
236  		goto out;
237  	}
238  	const char *errstr = NULL;
239  	if (pkg_abi_string_only_major_version(abi->os)) {
240  		abi->major = strtonum(version, 1, INT_MAX, &errstr);
241  	} else {
242  		/* XXX add tests for this */
243  		char *major = strsep(&version, ".");
244  		char *minor = strsep(&version, ".");
245  
246  		assert(major != NULL);
247  		if (minor == NULL) {
248  			pkg_emit_error("Invalid ABI string %s, "
249  			    "missing minor OS version", string);
250  			goto out;
251  		}
252  
253  		abi->major = strtonum(major, 1, INT_MAX, &errstr);
254  		if (errstr != NULL) {
255  			abi->minor = strtonum(minor, 1, INT_MAX, &errstr);
256  		}
257  	}
258  	if (errstr != NULL) {
259  		if (STREQ(version, "*")) {
260  			abi->major = 0;
261  			abi->minor = 0;
262  			abi->arch = PKG_ARCH_ANY;
263  			ret = true;
264  			goto out;
265  		}
266  		pkg_emit_error("Invalid version in ABI string '%s'", string);
267  		goto out;
268  	}
269  
270  	/* DragonFlyBSD continues to use the legacy/altabi format.
271  	   For example: dragonfly:5.10:x86:64
272  	   This means we can't use strsep again since that would split the arch
273  	   string for dragonfly. */
274  	char *arch = iter;
275  	if (arch == NULL) {
276  		pkg_emit_error("Invalid ABI string '%s', "
277  		    "missing architecture", string);
278  		goto out;
279  	}
280  
281  	abi->arch = pkg_arch_from_string(abi->os, arch);
282  	if (abi->arch == PKG_ARCH_UNKNOWN) {
283  		pkg_emit_error("Unknown architecture '%s' in ABI string", arch);
284  		goto out;
285  	}
286  
287  	if (abi->os == PKG_OS_DRAGONFLY && abi->arch != PKG_ARCH_AMD64) {
288  		pkg_emit_error("Invalid ABI string '%s', "
289  		    "only x86:64 is supported on dragonfly.", string);
290  		goto out;
291  	}
292  
293  	ret = true;
294  out:
295  	free(copy);
296  	return (ret);
297  }
298  
299  void
300  pkg_abi_set_freebsd_osversion(struct pkg_abi *abi, int osversion)
301  {
302  	assert(abi->os == PKG_OS_FREEBSD);
303  
304  	abi->major = osversion / 100000;
305  	abi->minor = (osversion / 1000) % 100;
306  	abi->patch = osversion % 1000;
307  }
308  
309  int
310  pkg_abi_get_freebsd_osversion(struct pkg_abi *abi)
311  {
312  	assert(abi->os == PKG_OS_FREEBSD);
313  
314  	return (abi->major * 100000) + (abi->minor * 1000) + abi->patch;
315  }
316  
317  int
318  pkg_abi_from_file(struct pkg_abi *abi)
319  {
320  	char rooted_abi_file[PATH_MAX];
321  	const char *abi_files[] = {
322  		getenv("ABI_FILE"),
323  		_PATH_UNAME,
324  		_PATH_BSHELL,
325  	};
326  	char work_abi_file[PATH_MAX];
327  	char work_arch_hint[PATH_MAX];
328  
329  	size_t i;
330  	int fd;
331  
332  	/*
333  	 * Perhaps not yet needed, but it may be in the future that there's no
334  	 * need to check root under some conditions where there is a rootdir.
335  	 * This also helps alleviate some excessive wrapping later.
336  	 */
337  	bool checkroot = ctx.pkg_rootdir != NULL;
338  	for (fd = -1, i = 0; i < NELEM(abi_files); i++) {
339  		if (abi_files[i] == NULL)
340  			continue;
341  
342  		const char *sep = strrchr(abi_files[i], '#');
343  		if (sep) {
344  			strlcpy(work_abi_file, abi_files[i],
345  			    MIN(sep - abi_files[i] + 1, sizeof(work_abi_file)));
346  			strlcpy(work_arch_hint, sep + 1,
347  			    sizeof(work_arch_hint));
348  		} else {
349  			strlcpy(work_abi_file, abi_files[i],
350  			    sizeof(work_abi_file));
351  			work_arch_hint[0] = '\0';
352  		}
353  
354  		/*
355  		 * Try prepending rootdir and using that if it exists.  If
356  		 * ABI_FILE is specified, assume that the consumer didn't want
357  		 * it mangled by rootdir.
358  		 */
359  		if (i > 0 && checkroot &&
360  		    snprintf(rooted_abi_file, PATH_MAX, "%s/%s",
361  			ctx.pkg_rootdir, work_abi_file) < PATH_MAX) {
362  			if ((fd = open(rooted_abi_file, O_RDONLY)) >= 0) {
363  				strlcpy(work_abi_file, rooted_abi_file,
364  				    sizeof(work_abi_file));
365  				break;
366  			}
367  		}
368  		if ((fd = open(work_abi_file, O_RDONLY)) >= 0) {
369  			break;
370  		}
371  		/* if the ABI_FILE was provided we only care about it */
372  		if (i == 0)
373  			break;
374  	}
375  	if (fd == -1) {
376  		pkg_emit_error(
377  		    "Unable to determine the ABI, none of the ABI_FILEs can be read.");
378  		return EPKG_FATAL;
379  	}
380  
381  
382  	int ret = pkg_elf_abi_from_fd(fd, abi);
383  	if (EPKG_OK != ret) {
384  		if (-1 == lseek(fd, 0, SEEK_SET)) {
385  			pkg_emit_errno("Error seeking file", work_abi_file);
386  			ret = EPKG_FATAL;
387  			goto close_out;
388  		}
389  
390  		enum pkg_arch arch_hint = PKG_ARCH_UNKNOWN;
391  		if (work_arch_hint[0]) {
392  			arch_hint = pkg_arch_from_string(PKG_OS_DARWIN, work_arch_hint);
393  			if (arch_hint == PKG_ARCH_UNKNOWN) {
394  				pkg_emit_error("Invalid ABI_FILE architecture hint %s",
395  				    work_arch_hint);
396  				ret = EPKG_FATAL;
397  				goto close_out;
398  			}
399  		}
400  
401  		ret = pkg_macho_abi_from_fd(fd, abi, arch_hint);
402  		if (EPKG_OK != ret) {
403  			pkg_emit_error(
404  			    "Unable to determine ABI, %s cannot be parsed.",
405  			    work_abi_file);
406  			ret = EPKG_FATAL;
407  			goto close_out;
408  		}
409  	}
410  
411  close_out:
412  	if (close(fd)) {
413  		pkg_emit_errno("Error closing file", work_abi_file);
414  		ret = EPKG_FATAL;
415  	}
416  	return ret;
417  }
418  
419  int
420  pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
421  {
422  	int i = 0;
423  	const struct arch_trans *arch_trans;
424  
425  	memset(dest, '\0', sz);
426  	/* Lower case the OS */
427  	while (arch[i] != ':' && arch[i] != '\0') {
428  		dest[i] = tolower(arch[i]);
429  		i++;
430  	}
431  	if (arch[i] == '\0')
432  		return (0);
433  
434  	dest[i++] = ':';
435  
436  	/* Copy the version */
437  	while (arch[i] != ':' && arch[i] != '\0') {
438  		dest[i] = arch[i];
439  		i++;
440  	}
441  	if (arch[i] == '\0')
442  		return (0);
443  
444  	dest[i++] = ':';
445  
446  	for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL;
447  	    arch_trans++) {
448  		if (STREQ(arch + i, arch_trans->archid)) {
449  			strlcpy(dest + i, arch_trans->elftype,
450  			    sz - (arch + i - dest));
451  			return (0);
452  		}
453  	}
454  	strlcpy(dest + i, arch + i, sz - (arch + i - dest));
455  
456  	return (0);
457  }
458  
459  void
460  pkg_cleanup_shlibs_required(struct pkg *pkg, charv_t *internal_provided)
461  {
462  	struct pkg_file *file = NULL;
463  	const char *lib;
464  
465  	vec_foreach(pkg->shlibs_required, i) {
466  		char *s = pkg->shlibs_required.d[i];
467  		if (charv_search(&pkg->shlibs_provided, s) != NULL ||
468  		    charv_search(internal_provided, s) != NULL) {
469  			pkg_debug(2,
470  			    "remove %s from required shlibs as the "
471  			    "package %s provides this library itself",
472  			    s, pkg->name);
473  			vec_remove_and_free(&pkg->shlibs_required, i, free);
474  			i--;
475  			continue;
476  		}
477  		if (charv_search(&pkg->shlibs_required_ignore, s) != NULL) {
478  			pkg_debug(2,
479  			    "remove %s from required shlibs for package %s as it "
480  			    "is listed in shlibs_required_ignore.",
481  			    s, pkg->name);
482  			vec_remove_and_free(&pkg->shlibs_required, i, free);
483  			i--;
484  			continue;
485  		}
486  		if (match_ucl_lists(s,
487  		    pkg_config_get("SHLIB_REQUIRE_IGNORE_GLOB"),
488  		    pkg_config_get("SHLIB_REQUIRE_IGNORE_REGEX"))) {
489  			pkg_debug(2,
490  			    "remove %s from required shlibs for package %s as it "
491  			    "is matched by SHLIB_REQUIRE_IGNORE_GLOB/REGEX.",
492  			    s, pkg->name);
493  			vec_remove(&pkg->shlibs_required, i);
494  			if (charv_insert_sorted(&pkg->shlibs_required_ignore, s) != NULL) {
495  				free(s);
496  			}
497  			i--;
498  			continue;
499  		}
500  		file = NULL;
501  		while (pkg_files(pkg, &file) == EPKG_OK) {
502  			if ((lib = strstr(file->path, s)) != NULL &&
503  			    strlen(lib) == strlen(s) && lib[-1] == '/') {
504  				pkg_debug(2,
505  				    "remove %s from required shlibs as "
506  				    "the package %s provides this file itself",
507  				    s, pkg->name);
508  
509  				vec_remove_and_free(&pkg->shlibs_required, i,
510  				    free);
511  				i--;
512  				break;
513  			}
514  		}
515  	}
516  }
517  
518  int
519  pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
520  {
521  	struct pkg_file *file = NULL;
522  	int ret = EPKG_OK;
523  	char fpath[MAXPATHLEN + 1];
524  	bool failures = false;
525  
526  	int (*pkg_analyse_init)(const char *stage);
527  	int (*pkg_analyse)(const bool developer_mode, struct pkg *pkg,
528  	    const char *fpath, char **provided, enum pkg_shlib_flags *flags);
529  	int (*pkg_analyse_close)(void);
530  
531  	if (0 == strncmp(pkg->abi, "Darwin", 6)) {
532  		pkg_analyse_init=pkg_analyse_init_macho;
533  		pkg_analyse=pkg_analyse_macho;
534  		pkg_analyse_close=pkg_analyse_close_macho;
535  	} else {
536  		pkg_analyse_init=pkg_analyse_init_elf;
537  		pkg_analyse=pkg_analyse_elf;
538  		pkg_analyse_close=pkg_analyse_close_elf;
539  	}
540  
541  	if (vec_len(&pkg->shlibs_required) != 0) {
542  		vec_free_and_free(&pkg->shlibs_required, free);
543  	}
544  
545  	if (vec_len(&pkg->shlibs_provided) != 0) {
546  		vec_free_and_free(&pkg->shlibs_provided, free);
547  	}
548  
549  	ret = pkg_analyse_init(stage);
550  	if (ret != EPKG_OK) {
551  		goto cleanup;
552  	}
553  
554  	/* Assume no architecture dependence, for contradiction */
555  	if (ctx.developer_mode)
556  		pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS |
557  		    PKG_CONTAINS_STATIC_LIBS | PKG_CONTAINS_LA);
558  
559  	/* shlibs that are provided by files in the package but not matched by
560  	   SHLIB_PROVIDE_PATHS_* are still used to filter the shlibs
561  	   required by the package */
562  	charv_t internal_provided = vec_init();
563  	/* list of shlibs that are in the path to be evaluated for provided but are symlinks */
564  	charv_t maybe_provided = vec_init();
565  
566  	while (pkg_files(pkg, &file) == EPKG_OK) {
567  		struct stat st;
568  		if (stage != NULL)
569  			snprintf(fpath, sizeof(fpath), "%s/%s", stage,
570  			    file->path);
571  		else
572  			strlcpy(fpath, file->path, sizeof(fpath));
573  
574  		char *provided = NULL;
575  		enum pkg_shlib_flags provided_flags = PKG_SHLIB_FLAGS_NONE;
576  
577  		ret = pkg_analyse(ctx.developer_mode, pkg, fpath, &provided, &provided_flags);
578  		if (EPKG_WARN == ret) {
579  			failures = true;
580  		}
581  
582  		if (provided != NULL) {
583  			const ucl_object_t *paths = NULL;
584  
585  			switch (provided_flags) {
586  			case PKG_SHLIB_FLAGS_NONE:
587  				paths = pkg_config_get("SHLIB_PROVIDE_PATHS_NATIVE");
588  				break;
589  			case PKG_SHLIB_FLAGS_COMPAT_32:
590  				paths = pkg_config_get("SHLIB_PROVIDE_PATHS_COMPAT_32");
591  				break;
592  			case PKG_SHLIB_FLAGS_COMPAT_LINUX:
593  				paths = pkg_config_get("SHLIB_PROVIDE_PATHS_COMPAT_LINUX");
594  				break;
595  			case PKG_SHLIB_FLAGS_COMPAT_LINUX_32:
596  				paths = pkg_config_get("SHLIB_PROVIDE_PATHS_COMPAT_LINUX_32");
597  				break;
598  			default:
599  				assert(0);
600  			}
601  			assert(paths != NULL);
602  
603  			if (lstat(fpath, &st) != 0) {
604  				pkg_emit_errno("lstat() failed for", fpath);
605  				free(provided);
606  				continue;
607  			}
608  			/* If the corresponding PATHS option isn't set (i.e. an empty ucl array)
609  			   don't do any filtering for backwards compatibility. */
610  			if (ucl_array_size(paths) == 0 || pkg_match_paths_list(paths, file->path)) {
611  				if (S_ISREG(st.st_mode)) {
612  					pkg_addshlib_provided(pkg, provided, provided_flags);
613  				} else {
614  					vec_push(&maybe_provided, pkg_shlib_name_with_flags(provided, provided_flags));
615  				}
616  			} else {
617  				vec_push(&internal_provided, pkg_shlib_name_with_flags(provided, provided_flags));
618  			}
619  			free(provided);
620  		}
621  	}
622  
623  	vec_foreach(maybe_provided, i) {
624  		vec_foreach(internal_provided, j) {
625  			if (STREQ(maybe_provided.d[i], internal_provided.d[j])) {
626  				pkg_addshlib_provided(pkg, maybe_provided.d[i], PKG_SHLIB_FLAGS_NONE);
627  				vec_remove_and_free(&internal_provided, j, free);
628  				j--;
629  			}
630  		}
631  		vec_remove_and_free(&maybe_provided, i, free);
632  		i--;
633  	}
634  	vec_free(&maybe_provided);
635  	/*
636  	 * Do not depend on libraries that a package provides itself
637  	 */
638  	pkg_cleanup_shlibs_required(pkg, &internal_provided);
639  	while (internal_provided.len > 0) {
640  		char *s = vec_pop(&internal_provided);
641  		if (charv_insert_sorted(&pkg->shlibs_provided_ignore, s) != NULL) {
642  			free(s);
643  		}
644  	}
645  
646  	vec_foreach(pkg->shlibs_provided, i) {
647  		char *s = pkg->shlibs_provided.d[i];
648  		if (charv_search(&pkg->shlibs_provided_ignore, s) != NULL) {
649  			pkg_debug(2,
650  			    "remove %s from provided shlibs for package %s as it "
651  			    "is listed in shlibs_provided_ignore.",
652  			    s, pkg->name);
653  			vec_remove_and_free(&pkg->shlibs_provided, i, free);
654  			i--;
655  			continue;
656  		}
657  		if (match_ucl_lists(s,
658  		    pkg_config_get("SHLIB_PROVIDE_IGNORE_GLOB"),
659  		    pkg_config_get("SHLIB_PROVIDE_IGNORE_REGEX"))) {
660  			pkg_debug(2,
661  			    "remove %s from provided shlibs for package %s as it "
662  			    "is matched by SHLIB_PROVIDE_IGNORE_GLOB/REGEX.",
663  			    s, pkg->name);
664  			vec_remove(&pkg->shlibs_provided, i);
665  			if (charv_insert_sorted(&pkg->shlibs_provided_ignore, s) != NULL) {
666  				free(s);
667  			}
668  			i--;
669  			continue;
670  		}
671  	}
672  
673  	/*
674  	 * if the package is not supposed to provide share libraries then
675  	 * drop the provided one
676  	 */
677  	if (pkg_kv_get(&pkg->annotations, "no_provide_shlib") != NULL) {
678  		vec_free_and_free(&pkg->shlibs_provided, free);
679  	}
680  
681  	if (failures)
682  		goto cleanup;
683  
684  	ret = EPKG_OK;
685  
686  cleanup:
687  	ret = pkg_analyse_close();
688  
689  	return (ret);
690  }