2

For a java application running on a linux system, how can I determine the underlying version of glibc?

Background: I'd like to, at runtime, determine if it possible to use conscrypt, which appears to require glibc 2.14 nowadays (https://github.com/google/conscrypt/pull/589), but I would still need to gracefully support running on CentOS 6 or other older distributions by falling back to the standard Java SSL code. Unfortunately (at least as far as I've been able to determine) there's no way to catch and recover from the error that occurs if Conscrypt is initialised on an older distribution, but if I can determine the glibc version I could choose whether to initialise it based on that.

Philip Withnall
  • 5,293
  • 14
  • 28
Matt Sheppard
  • 116,545
  • 46
  • 111
  • 131
  • Run `ldd --version` command from Java and check the output. See https://stackoverflow.com/a/20155150/5221149 – Andreas Jan 18 '19 at 00:26
  • 1
    Is there some official format to parse the output based on? Or failing that, is the output format known to be stable? – Matt Sheppard Jan 18 '19 at 00:31
  • Maybe related, [Calling C++ from Java, but Java loads the wrong Glibc version](https://stackoverflow.com/q/22550611/608639) – jww Jan 18 '19 at 02:07

2 Answers2

2

Working example of executing ldd --version and parsing the response for the version number.

public class Main {

    public static void main(String[] args) throws IOException {
        final ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash").command("ldd --version");
        processBuilder.redirectErrorStream(true);

        final Process process = processBuilder.start();
        final StringBuilder stream = readStream(process.getInputStream());

        final String version = getVersion(stream.toString());

        System.out.println(version);
    }

    /**
     * Read the output stream of the process
     *
     * @param iStream InputStream
     * @return StringBuilder containing the output of the command
     */
    private static StringBuilder readStream(InputStream iStream) throws IOException {
        final StringBuilder builder = new StringBuilder();
        String line;

        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(iStream))) {
            while ((line = bufferedReader.readLine()) != null) {
                builder.append(line);
                builder.append(System.getProperty("line.separator"));
            }
        }

        return builder;
    }

    /**
     * Parse the response for the version number.
     *
     * @param input String response of ldd --version
     * @return String of the version, or null if not found
     */
    private static String getVersion(String input) {
        final Pattern pattern = Pattern.compile("[-+]?[0-9]*\\.?[0-9]+");
        final Matcher matcher = pattern.matcher(input);

        return matcher.find() ? matcher.group() : null;
    }
}
Chris
  • 3,437
  • 6
  • 40
  • 73
  • Do you have to run the command in Bash rather than just running the command? What's the advantage to going through Bash? – Boris the Spider Jan 18 '19 at 00:49
  • And why do you care about the system line separator? Seems redundant to take text line by line then stick it back together just to parse it again. Wouldn't using a `List` make more sense? Either that or just dump the output directly into a `String` without the intermediate splitting by line. – Boris the Spider Jan 18 '19 at 00:51
  • Sure, to be fair it was mostly a copy-paste and a wee tweak from a current project I have open. Didn't say it was production ready but it will do what the OP is asking for. – Chris Jan 18 '19 at 00:55
0

I assume you use some pre-built binary. You should be able to catch the java.lang.UnsatisfiedLinkError exception thrown by the java.lang.System.load(String) method. If the JNI shared object is linked correctly, the dynamic linker will detect the missing symbol versions (presumably GLIBC_2.14) even if lazy binding is active.

Alternatively, I don't see anything in Conscrypt which would preclude building on CentOS 6 (with the Developer Toolset software collection for a C++11 compiler). It's a bit involved, but the glibc 2.14 dependency seems to be something that comes from the way the pre-built binaries are made, and it's not inherent to the software itself.

Florian Weimer
  • 32,022
  • 3
  • 48
  • 92