/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "alloc-util.h" #include "glob-util.h" #include "log.h" #include "nspawn-util.h" #include "parse-util.h" #include "path-util.h" #include "string-util.h" int systemd_installation_has_version(const char *root, const char *minimal_version) { bool found = false; int r; /* Try to guess if systemd installation is later than the specified version. This * is hacky and likely to yield false negatives, particularly if the installation * is non-standard. False positives should be relatively rare. */ FOREACH_STRING(pattern, /* /lib works for systems without usr-merge, and for systems with a sane * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary * for Gentoo which does a merge without making /lib a symlink. * Also support multiarch paths von Debian/Ubuntu; *-linux-* is a small * optimization based on the naming scheme of existing multiarch tuples. */ "/lib/systemd/libsystemd-shared-*.so", "/lib64/systemd/libsystemd-shared-*.so", "/usr/lib/*-linux-*/systemd/libsystemd-shared-*.so", "/usr/lib/systemd/libsystemd-shared-*.so", "/usr/lib64/systemd/libsystemd-shared-*.so") { _cleanup_strv_free_ char **names = NULL; _cleanup_free_ char *path = NULL; char *c; path = path_join(root, pattern); if (!path) return -ENOMEM; r = glob_extend(&names, path, 0); if (r == -ENOENT) continue; if (r < 0) return r; assert_se(c = endswith(path, "*.so")); *c = '\0'; /* truncate the glob part */ STRV_FOREACH(name, names) { _cleanup_free_ char *bn = NULL; /* This is most likely to run only once, hence let's not optimize anything. */ char *t, *t2; if (path_extract_filename(*name, &bn) < 0) continue; t = startswith(bn, "libsystemd-shared-"); if (!t) continue; t2 = endswith(t, ".so"); if (!t2) continue; *t2 = '\0'; found = true; r = strverscmp_improved(t, minimal_version); log_debug("Found libsystemd shared at \"%s.so\", version %s (%s).", *name, t, r >= 0 ? "OK" : "too old"); if (r >= 0) return true; } } return !found ? -ENOENT : false; }