/* 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;
}
