]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
path-util: add a function to peek into a container and guess systemd version
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 2 Oct 2016 13:51:27 +0000 (15:51 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 8 Oct 2016 18:48:41 +0000 (14:48 -0400)
This is a bit crude and only works for new systemd versions which
have libsystemd-shared.

src/basic/path-util.c
src/basic/path-util.h
src/test/test-path-util.c

index b2fa81a294c46cf2e3898a2c47c195fef0902356..c32e961af470783bbe118ff90dbc93e901ed5523 100644 (file)
 #include "alloc-util.h"
 #include "extract-word.h"
 #include "fs-util.h"
+#include "glob-util.h"
 #include "log.h"
 #include "macro.h"
 #include "missing.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "stat-util.h"
 #include "string-util.h"
@@ -814,3 +816,69 @@ bool is_device_path(const char *path) {
                 path_startswith(path, "/dev/") ||
                 path_startswith(path, "/sys/");
 }
+
+int systemd_installation_has_version(const char *root, unsigned minimal_version) {
+        const char *pattern;
+        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.
+         */
+
+        NULSTR_FOREACH(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.
+                        */
+                       "lib/systemd/libsystemd-shared-*.so\0"
+                       "usr/lib/systemd/libsystemd-shared-*.so\0") {
+
+                _cleanup_strv_free_ char **names = NULL;
+                _cleanup_free_ char *path = NULL;
+                char *c, **name;
+
+                path = prefix_root(root, pattern);
+                if (!path)
+                        return -ENOMEM;
+
+                r = glob_extend(&names, path);
+                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) {
+                        /* This is most likely to run only once, hence let's not optimize anything. */
+                        char *t, *t2;
+                        unsigned version;
+
+                        t = startswith(*name, path);
+                        if (!t)
+                                continue;
+
+                        t2 = endswith(t, ".so");
+                        if (!t2)
+                                continue;
+
+                        t2[0] = '\0'; /* truncate the suffix */
+
+                        r = safe_atou(t, &version);
+                        if (r < 0) {
+                                log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
+                                continue;
+                        }
+
+                        log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
+                                  *name, version,
+                                  version >= minimal_version ? "OK" : "too old");
+                        if (version >= minimal_version)
+                                return true;
+                }
+        }
+
+        return false;
+}
index a27c13fcc3a94cd0ae525d63dee7d1c6ec31fa86..78472f0961a142786df34ba5bf31776ac134eeef 100644 (file)
@@ -125,3 +125,5 @@ char *file_in_same_dir(const char *path, const char *filename);
 bool hidden_or_backup_file(const char *filename) _pure_;
 
 bool is_device_path(const char *path);
+
+int systemd_installation_has_version(const char *root, unsigned minimal_version);
index 164a10d8a8800cf84c13dad3f3d7cc9919f76a3f..0b10d8e25ed011785ae644a29e105a0cb095bb36 100644 (file)
@@ -511,7 +511,24 @@ static void test_hidden_or_backup_file(void) {
         assert_se(!hidden_or_backup_file("test.dpkg-old.foo"));
 }
 
+static void test_systemd_installation_has_version(const char *path) {
+        int r;
+        const unsigned versions[] = {0, 231, atoi(PACKAGE_VERSION), 999};
+        unsigned i;
+
+        for (i = 0; i < ELEMENTSOF(versions); i++) {
+                r = systemd_installation_has_version(path, versions[i]);
+                assert_se(r >= 0);
+                log_info("%s has systemd >= %u: %s",
+                         path ?: "Current installation", versions[i], yes_no(r));
+        }
+}
+
 int main(int argc, char **argv) {
+        log_set_max_level(LOG_DEBUG);
+        log_parse_environment();
+        log_open();
+
         test_path();
         test_find_binary(argv[0]);
         test_prefixes();
@@ -526,5 +543,7 @@ int main(int argc, char **argv) {
         test_filename_is_valid();
         test_hidden_or_backup_file();
 
+        test_systemd_installation_has_version(argv[1]); /* NULL is OK */
+
         return 0;
 }