There is a long standing limitation in the UNIX smartcardio implementation 
which means it will only look for the `pcsclite` library in two locations; 
`/usr/lib` and `/usr/local/lib`. It also only searches for an unversioned 
library.

On systems that separate libraries from development headers in separate 
subpackages, the unversioned library is only installed by the `-devel` package, 
which rarely happens unless the user wants to write their own application using 
the libpcsclite headers or build someone else's code themselves. An example of 
this is the [pcsc-lite-libs package on 
Fedora](https://koji.fedoraproject.org/koji/rpminfo?rpmID=35258843)

On Debian-based systems, there is also the issue that libraries are now placed 
inside a subdirectory using a [tuple](https://wiki.debian.org/Multiarch/Tuples) 
consisting of the instruction set, syscall ABI and libc e.g. 
`x86_64-linux-gnu`.  So it will not only fail to find the library when only the 
versioned library is installed (e.g. 
[libpcsclite1](https://packages.ubuntu.com/kinetic/amd64/libpcsclite1/filelist))
 but also when the dev package is also installed (e.g. 
[libpcsclite-dev](https://packages.ubuntu.com/kinetic/amd64/libpcsclite-dev/filelist)),
 because the file is in e.g. `/usr/lib/x86_64-linux-gnu/libpcsclite.so`

This patch makes both cases work. It prefers versioned libraries, as 
potentially a `libpcsclite.so.2` could become available with a different ABI 
that the JDK can not work with.  All cases that worked before with just 
`libpcsclite.so` will still work, but it should also now pick up the library on 
many additional systems.

A much simpler patch (search for the versioned symlink instead of unversioned) 
has been [in the Fedora and RHEL packages for nearly a 
decade](https://bugzilla.redhat.com/show_bug.cgi?id=910107), and an earlier 
version of this patch with Debian support has been used in IcedTea builds since 
2015. It would be nice to finally fix this upstream.

Testing:

Test case:
~~~
import java.lang.reflect.Method;

public class TestPlatformPCSC {
    public static void main(String[] args)
    throws Exception {
        Class<?> cls = Class.forName("sun.security.smartcardio.PlatformPCSC");
        Method m = cls.getDeclaredMethod("getLibraryName");
        m.setAccessible(true);
        System.err.println(m.invoke(null));
    }
}
~~~

1. With `libpcsclite.so.1` available:
~~~
$ ~/builder/trunk/images/jdk/bin/java --add-opens 
java.smartcardio/sun.security.smartcardio=ALL-UNNAMED 
-Djava.security.debug=pcsc TestPlatformPCSC
pcsc: Looking for /usr/lib64/libpcsclite.so.1
pcsc: Using PC/SC library: /usr/lib64/libpcsclite.so.1
pcsc: Looking for /usr/lib64/libpcsclite.so.1
/usr/lib64/libpcsclite.so.1
~~~

2. With just `libpcsclite.so` available:
~~~
$ ~/builder/trunk/images/jdk/bin/java --add-opens 
java.smartcardio/sun.security.smartcardio=ALL-UNNAMED 
-Djava.security.debug=pcsc TestPlatformPCSC
pcsc: Looking for /usr/lib64/libpcsclite.so.1
pcsc: Looking for /usr/lib64/libpcsclite.so.0
pcsc: Looking for /usr/lib64/libpcsclite.so
pcsc: Using PC/SC library: /usr/lib64/libpcsclite.so
~~~

4. With `libpcsclite.so.1` in the Debian-style structure:
~~~
$ ~/builder/trunk/images/jdk/bin/java --add-opens 
java.smartcardio/sun.security.smartcardio=ALL-UNNAMED 
-Djava.security.debug=pcsc TestPlatformPCSC
pcsc: Looking for /usr/lib64/libpcsclite.so.1
pcsc: Looking for /usr/lib64/libpcsclite.so.0
pcsc: Looking for /usr/lib64/libpcsclite.so
pcsc: Looking for /usr/local/lib64/libpcsclite.so.1
pcsc: Looking for /usr/local/lib64/libpcsclite.so.0
pcsc: Looking for /usr/local/lib64/libpcsclite.so
pcsc: Looking for /usr/lib/x86_64-linux-gnu/libpcsclite.so.1
pcsc: Using PC/SC library: /usr/lib/x86_64-linux-gnu/libpcsclite.so.1
~~~

5. Without the library installed
~~~
$ ~/builder/trunk/images/jdk/bin/java --add-opens 
java.smartcardio/sun.security.smartcardio=ALL-UNNAMED 
-Djava.security.debug=pcsc TestPlatformPCSC
pcsc: Looking for /usr/lib64/libpcsclite.so.1
pcsc: Looking for /usr/lib64/libpcsclite.so.0
pcsc: Looking for /usr/lib64/libpcsclite.so
pcsc: Looking for /usr/local/lib64/libpcsclite.so.1
pcsc: Looking for /usr/local/lib64/libpcsclite.so.0
pcsc: Looking for /usr/local/lib64/libpcsclite.so
pcsc: Looking for /usr/lib/x86_64-linux-gnu/libpcsclite.so.1
pcsc: Looking for /usr/lib/x86_64-linux-gnu/libpcsclite.so.0
pcsc: Looking for /usr/lib/x86_64-linux-gnu/libpcsclite.so
pcsc: Looking for /usr/lib/arm-linux-gnueabi/libpcsclite.so.1
pcsc: Looking for /usr/lib/arm-linux-gnueabi/libpcsclite.so.0
pcsc: Looking for /usr/lib/arm-linux-gnueabi/libpcsclite.so
pcsc: Looking for /usr/lib/arm-linux-gnueabihf/libpcsclite.so.1
pcsc: Looking for /usr/lib/arm-linux-gnueabihf/libpcsclite.so.0
pcsc: Looking for /usr/lib/arm-linux-gnueabihf/libpcsclite.so
pcsc: Looking for /usr/lib/x86_64-kfreebsd-gnu/libpcsclite.so.1
pcsc: Looking for /usr/lib/x86_64-kfreebsd-gnu/libpcsclite.so.0
pcsc: Looking for /usr/lib/x86_64-kfreebsd-gnu/libpcsclite.so
pcsc: Looking for /usr/lib64/libpcsclite.so.1
pcsc: Looking for /usr/lib64/libpcsclite.so.0
pcsc: Looking for /usr/lib64/libpcsclite.so
pcsc: Looking for /usr/local/lib64/libpcsclite.so.1
pcsc: Looking for /usr/local/lib64/libpcsclite.so.0
pcsc: Looking for /usr/local/lib64/libpcsclite.so
pcsc: Looking for /usr/lib/x86_64-linux-gnu/libpcsclite.so.1
pcsc: Looking for /usr/lib/x86_64-linux-gnu/libpcsclite.so.0
pcsc: Looking for /usr/lib/x86_64-linux-gnu/libpcsclite.so
pcsc: Looking for /usr/lib/arm-linux-gnueabi/libpcsclite.so.1
pcsc: Looking for /usr/lib/arm-linux-gnueabi/libpcsclite.so.0
pcsc: Looking for /usr/lib/arm-linux-gnueabi/libpcsclite.so
pcsc: Looking for /usr/lib/arm-linux-gnueabihf/libpcsclite.so.1
pcsc: Looking for /usr/lib/arm-linux-gnueabihf/libpcsclite.so.0
pcsc: Looking for /usr/lib/arm-linux-gnueabihf/libpcsclite.so
pcsc: Looking for /usr/lib/x86_64-kfreebsd-gnu/libpcsclite.so.1
pcsc: Looking for /usr/lib/x86_64-kfreebsd-gnu/libpcsclite.so.0
pcsc: Looking for /usr/lib/x86_64-kfreebsd-gnu/libpcsclite.so
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at 
java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at TestPlatformPCSC.main(TestPlatformPCSC.java:9)
Caused by: java.io.IOException: No PC/SC library found on this system
~~~

-------------

Commit messages:
 - 8009550: PlatformPCSC should load versioned so

Changes: https://git.openjdk.org/jdk/pull/15409/files
 Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=15409&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8009550
  Stats: 53 lines in 2 files changed: 29 ins; 4 del; 20 mod
  Patch: https://git.openjdk.org/jdk/pull/15409.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/15409/head:pull/15409

PR: https://git.openjdk.org/jdk/pull/15409

Reply via email to