Branch data Line data Source code
1 : : /*- 2 : : * Copyright (c) 1998 John D. Polstra 3 : : * Copyright (c) 2012 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 : : 12 : : #include <assert.h> 13 : : #include <ctype.h> 14 : : #include <dirent.h> 15 : : #include <errno.h> 16 : : #include <string.h> 17 : : 18 : : #include "pkg.h" 19 : : #include "pkghash.h" 20 : : #include "private/event.h" 21 : : #include "private/pkg.h" 22 : : #include "xmalloc.h" 23 : : 24 : : static int 25 : 495 : scan_dir_for_shlibs(pkghash **shlib_list, const char *dir, 26 : : enum pkg_shlib_flags flags) 27 : : { 28 : 495 : DIR *dirp= opendir(dir); 29 [ + + ]: 495 : if (dirp == NULL) { 30 [ + - ]: 228 : if (errno == ENOENT) { 31 : 228 : return (EPKG_OK); 32 : : } 33 : 0 : pkg_errno("Failed to open '%s' to scan for shared libraries", dir); 34 : 0 : return (EPKG_FATAL); 35 : : } 36 : : 37 : : struct dirent *dp; 38 [ + + ]: 47793 : while ((dp = readdir(dirp)) != NULL) { 39 : : /* Only regular files and sym-links. On some 40 : : filesystems d_type is not set, on these the d_type 41 : : field will be DT_UNKNOWN. */ 42 [ + + + + : 47526 : if (dp->d_type != DT_REG && dp->d_type != DT_LNK && - + ] 43 : 1602 : dp->d_type != DT_UNKNOWN) 44 : 1602 : continue; 45 : : 46 : 45924 : int len = strlen(dp->d_name); 47 : : /* Name can't be shorter than "libx.so" */ 48 [ + + + + ]: 45924 : if (len < 7 || strncmp(dp->d_name, "lib", 3) != 0) 49 : 5785 : continue; 50 : : 51 : 40139 : const char *vers = dp->d_name + len; 52 [ - + + + ]: 111072 : while (vers > dp->d_name && 53 [ + + + + ]: 70933 : (isdigit(*(vers-1)) || *(vers-1) == '.')) 54 : 30794 : vers--; 55 [ + + ]: 40139 : if (vers == dp->d_name + len) { 56 [ + + ]: 25632 : if (strncmp(vers - 3, ".so", 3) != 0) 57 : 12549 : continue; 58 [ + - - + ]: 27590 : } else if (vers < dp->d_name + 3 || 59 : 14507 : strncmp(vers - 3, ".so.", 4) != 0) 60 : 0 : continue; 61 : : 62 : : /* We have a valid shared library name. */ 63 : 27590 : char *full = pkg_shlib_name_with_flags(dp->d_name, flags); 64 [ + + - + ]: 55091 : pkghash_safe_add(*shlib_list, full, NULL, NULL); 65 : 27590 : free(full); 66 : : } 67 : : 68 : 267 : closedir(dirp); 69 : : 70 : 267 : return (EPKG_OK); 71 : 495 : } 72 : : 73 : : static struct { 74 : : const char *dir; 75 : : enum pkg_shlib_flags flags; 76 : : } system_shlib_table[] = { 77 : : {"/lib", PKG_SHLIB_FLAGS_NONE }, 78 : : {"/usr/lib", PKG_SHLIB_FLAGS_NONE }, 79 : : {"/usr/lib32", PKG_SHLIB_FLAGS_COMPAT_32 }, 80 : : }; 81 : : 82 : : int 83 : 165 : scan_system_shlibs(pkghash **system_shlibs, const char *rootdir) 84 : : { 85 [ + + ]: 660 : for (int i = 0; i < NELEM(system_shlib_table); i++) { 86 : : char *dir; 87 [ + + ]: 495 : if (rootdir != NULL) { 88 : 228 : xasprintf(&dir, "%s%s", rootdir, system_shlib_table[i].dir); 89 : 228 : } else { 90 : 267 : dir = xstrdup(system_shlib_table[i].dir); 91 : : } 92 : 495 : int ret = scan_dir_for_shlibs(system_shlibs, dir, system_shlib_table[i].flags); 93 : 495 : free(dir); 94 [ - + ]: 495 : if (ret != EPKG_OK) { 95 : 0 : return (ret); 96 : : } 97 : 495 : } 98 : : 99 : 165 : return (EPKG_OK); 100 : 165 : }