1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include "alloc-util.h"
4 #include "glob-util.h"
5 #include "log.h"
6 #include "nspawn-util.h"
7 #include "parse-util.h"
8 #include "path-util.h"
9 #include "string-util.h"
10 
systemd_installation_has_version(const char * root,const char * minimal_version)11 int systemd_installation_has_version(const char *root, const char *minimal_version) {
12         int r;
13 
14         /* Try to guess if systemd installation is later than the specified version. This
15          * is hacky and likely to yield false negatives, particularly if the installation
16          * is non-standard. False positives should be relatively rare.
17          */
18 
19         FOREACH_STRING(pattern,
20                        /* /lib works for systems without usr-merge, and for systems with a sane
21                         * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
22                         * for Gentoo which does a merge without making /lib a symlink.
23                         */
24                        "/lib/systemd/libsystemd-shared-*.so",
25                        "/lib64/systemd/libsystemd-shared-*.so",
26                        "/usr/lib/systemd/libsystemd-shared-*.so",
27                        "/usr/lib64/systemd/libsystemd-shared-*.so") {
28 
29                 _cleanup_strv_free_ char **names = NULL;
30                 _cleanup_free_ char *path = NULL;
31                 char *c;
32 
33                 path = path_join(root, pattern);
34                 if (!path)
35                         return -ENOMEM;
36 
37                 r = glob_extend(&names, path, 0);
38                 if (r == -ENOENT)
39                         continue;
40                 if (r < 0)
41                         return r;
42 
43                 assert_se(c = endswith(path, "*.so"));
44                 *c = '\0'; /* truncate the glob part */
45 
46                 STRV_FOREACH(name, names) {
47                         /* This is most likely to run only once, hence let's not optimize anything. */
48                         char *t, *t2;
49 
50                         t = startswith(*name, path);
51                         if (!t)
52                                 continue;
53 
54                         t2 = endswith(t, ".so");
55                         if (!t2)
56                                 continue;
57                         *t2 = '\0';
58 
59                         r = strverscmp_improved(t, minimal_version);
60                         log_debug("Found libsystemd shared at \"%s.so\", version %s (%s).",
61                                   *name, t,
62                                   r >= 0 ? "OK" : "too old");
63                         if (r >= 0)
64                                 return true;
65                 }
66         }
67 
68         return false;
69 }
70