从Linux 64位访问javax.smartcardio

我正在尝试使用javax.smartcardio API加载智能卡终端,代码如下:

public CardTerminal getReadyCardTerminal() throws CardException { TerminalFactory factory = TerminalFactory.getDefault(); CardTerminals terminals = factory.terminals(); List list = terminals.list(State.CARD_PRESENT); while (list.isEmpty()) { terminals.waitForChange(1000); list = terminals.list(State.CARD_PRESENT); } CardTerminal cardTerminal = list.get(0); return cardTerminal; } 

…而且我总是得到以下exception:

 java.lang.IllegalStateException: no terminals at javax.smartcardio.TerminalFactory$NoneCardTerminals.waitForChange(TerminalFactory.java:145) 

在Windows Vista / 7上一切正常,但我不能让它在Linux上运行。 我正在使用Ubuntu 12.04 64位。

我使用以下命令安装了pcscd服务:

 sudo apt-get install libccid pcscd libpcsclite-dev libpcsclite1 sudo service pcscd start 

并且pcsc_scan命令打印出:

 PC/SC device scanner V 1.4.18 (c) 2001-2011, Ludovic Rousseau  Compiled with PC/SC lite version: 1.7.4 Using reader plug'n play mechanism Scanning present readers... 0: OMNIKEY CardMan 3x21 00 00 Tue Sep 11 15:44:49 2012 Reader 0: OMNIKEY CardMan 3x21 00 00 Card state: Card inserted, ATR:  ... 

所以一切看起来都不错,但智能卡只是不起作用。 我正在尝试使用Oracle和OpenJDK 1.7.0_05,32和64位。

在Ubuntu 32位环境下,代码可以运行OpenJDK(但不是Oracle JDK,不知道为什么)。 所以我认为从Java到PC / SC库的64位桥接器存在问题。

有任何想法吗?

谢谢。

我想我找到了一个解决方法,因为我遇到了类似的问题。 在来自ubuntu的bug报告中,它说javax.smartcardio库在错误的目录中搜索PC / SC库。

通过在我的机器上指定PC / SC库的路径,就像bugreport提到的那样,我得到了它的工作。

bug报告中的路径对我来说是错误的,我在64位fedora上,其中pc / sc库安装在/usr/lib64/libpcsclite.so.1

所以我的解决方法是指定java的库路径,如下所示:

 java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1 

根据您的Linux发行版, libpcsclite.so.1的位置实际上可能不同,它也可能位于/lib/x86_64-linux-gnu/libpcsclite.so.1 (即Kubuntu 15.04)。 在这种情况下,请将其称为:

 java -Dsun.security.smartcardio.library=/lib/x86_64-linux-gnu/libpcsclite.so.1 

我正在使用带有debian arm版本的覆盆子

首先找到libpcsclite的位置:

 $ ldd -r /usr/bin/pcsc_scan 

然后使用libpcsclite位置:

 java -Dsun.security.smartcardio.library=/usr/lib/arm-linux-gnueabihf/libpcsclite.so.1 

对于其他任何在64位计算机上使用Ubuntu 14进行此操作的人。 我发现.so文件实际上位于以下目录中

/usr/lib/x86_64-linux-gnu/libpcsclite.so

所以使用下面的设置运行我的应用程序对我有用

-Dsun.security.smartcardio.library = / usr / lib中/ x86_64的-Linux的GNU / libpcsclite.so

您需要在调用程序时给出libpcsclite.so.1的路径,如下所示

java -Dsun.security.smartcardio.library=/path/to/libpcsclite.so.1

如果您不知道库的路径,请使用以下命令

 find /usr/lib -name libpcsclite.so.1 

这通常会显示机器上的路径。 我在Ubuntu 10(32位)和Ubuntu 15(32位和64位)上使用它

如果你像我一样懒,你可以做的是在你使用javax.smartcardio库之前在程序中包含这部分代码

  try { String comm[] = { "find", "/usr", "/lib", "-name", "libpcsclite.so.1" }; Process p = Runtime.getRuntime().exec(comm); BufferedReader reader = new BufferedReader( new InputStreamReader(p.getInputStream())); while ((line = reader.readLine()) != null && !line.equals("")) { if (line.contains("libpcsclite.so.1")) { System.setProperty("sun.security.smartcardio.library",line); break; } } p.waitFor(); } catch (Exception e) { e.printStackTrace(); } 

现在,您可以像往常一样运行代码,而不包括libpcsclite.so.1的路径

除了提供路径作为参数的解决方案,如下所示:

 java -Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1 

如果您不想在每次调用JVM时都提供此项,请在环境变量_JAVA_OPTIONS和/或JAVA_OPTS中设置它:

 export _JAVA_OPTIONS="-Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1" export JAVA_OPTS="-Dsun.security.smartcardio.library=/usr/lib64/libpcsclite.so.1" 

由于这是影响整个系统的bug的解决方法,因此恕我直言也可以在全系统范围内应用此解决方法。

JAVA_OPTS具有本地范围,必须由运行代码的脚本进行评估; _JAVA_OPTIONS应该由JRE自动评估。

另一种方法(我最喜欢的)是制作一些符号链接。

它的优点是它在系统范围内工作(没有jvm参数,没有环境变量)。

对于我的(心爱的)debian jessie amd64:

 ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so libpcsclite.so ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so.1 libpcsclite.so.1 ln -s /usr/lib/x86_64-linux-gnu/libpcsclite.so.1.0.0 libpcsclite.so.1.0.0 

注意:这可能需要超级用户访问权限。