Skip to content

Commit

Permalink
nativeaccess: try to load all located libsystemds (#108238)
Browse files Browse the repository at this point in the history
Linux systems with multiarch (e.g. i386 & x86_64) libraries
may have libsystemd.0 in two subdirectories of an entry in
java.library.path. For example, libsystemd.so.0 may be found
in both /usr/lib/i386-linux-gnu and /usr/lib/x86_64-linux-gnu.

Instead of attempting to load any library found, attempt all
and stop as soon as one is successfully loaded.
  • Loading branch information
axw committed May 8, 2024
1 parent 87df295 commit 5a622b0
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 20 deletions.
6 changes: 6 additions & 0 deletions docs/changelog/108238.yaml
@@ -0,0 +1,6 @@
pr: 108238
summary: "Nativeaccess: try to load all located libsystemds"
area: Infra/Core
type: bug
issues:
- 107878
Expand Up @@ -17,7 +17,10 @@
import java.lang.foreign.MemorySegment;
import java.lang.invoke.MethodHandle;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;

import static java.lang.foreign.ValueLayout.ADDRESS;
import static java.lang.foreign.ValueLayout.JAVA_INT;
Expand All @@ -26,31 +29,49 @@
class JdkSystemdLibrary implements SystemdLibrary {

static {
System.load(findLibSystemd());
}

// On some systems libsystemd does not have a non-versioned symlink. System.loadLibrary only knows how to find
// non-versioned library files. So we must manually check the library path to find what we need.
static String findLibSystemd() {
final String libsystemd = "libsystemd.so.0";
String libpath = System.getProperty("java.library.path");
for (String basepathStr : libpath.split(":")) {
var basepath = Paths.get(basepathStr);
if (Files.exists(basepath) == false) {
continue;
// Find and load libsystemd. We attempt all instances of
// libsystemd in case of multiarch systems, and stop when
// one is successfully loaded. If none can be loaded,
// UnsatisfiedLinkError will be thrown.
List<String> paths = findLibSystemd();
if (paths.isEmpty()) {
String libpath = System.getProperty("java.library.path");
throw new UnsatisfiedLinkError("Could not find libsystemd in java.library.path: " + libpath);
}
UnsatisfiedLinkError last = null;
for (String path : paths) {
try {
System.load(path);
last = null;
break;
} catch (UnsatisfiedLinkError e) {
last = e;
}
try (var stream = Files.walk(basepath)) {
}
if (last != null) {
throw last;
}
}

var foundpath = stream.filter(Files::isDirectory).map(p -> p.resolve(libsystemd)).filter(Files::exists).findAny();
if (foundpath.isPresent()) {
return foundpath.get().toAbsolutePath().toString();
}
// findLibSystemd returns a list of paths to instances of libsystemd
// found within java.library.path.
static List<String> findLibSystemd() {
// Note: on some systems libsystemd does not have a non-versioned symlink.
// System.loadLibrary only knows how to find non-versioned library files,
// so we must manually check the library path to find what we need.
final Path libsystemd = Paths.get("libsystemd.so.0");
final String libpath = System.getProperty("java.library.path");
return Arrays.stream(libpath.split(":")).map(Paths::get).filter(Files::exists).flatMap(p -> {
try {
return Files.find(
p,
Integer.MAX_VALUE,
(fp, attrs) -> (attrs.isDirectory() == false && fp.getFileName().equals(libsystemd))
);
} catch (IOException e) {
throw new UncheckedIOException(e);
}

}
throw new UnsatisfiedLinkError("Could not find " + libsystemd + " in java.library.path: " + libpath);
}).map(p -> p.toAbsolutePath().toString()).toList();
}

private static final MethodHandle sd_notify$mh = downcallHandle("sd_notify", FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS));
Expand Down

0 comments on commit 5a622b0

Please sign in to comment.