Доступ к javax.smartcardio из Linux 64 бит
Я пытаюсь загрузить терминалы смарт-карт с помощью javax.smartcardio API со следующим кодом:
public CardTerminal getReadyCardTerminal() throws CardException {
TerminalFactory factory = TerminalFactory.getDefault();
CardTerminals terminals = factory.terminals();
List<CardTerminal> 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;
}
... и я получаю следующее исключение:
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 <[email protected]>
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: <some hexa codes>
...
Итак, все выглядит нормально, но смарткардио просто не работает. Я пытаюсь как с Oracle, так и с OpenJDK 1.7.0_05, 32 и 64 бит.
Код работает нормально с OpenJDK (но не с Oracle JDK, не знаю, почему) в среде 32 бит Ubuntu. Поэтому я думаю, что это проблема с 64-битным мостом от Java до библиотеки ПК /SC.
Любые идеи?
Спасибо.
Ответы
Ответ 1
Я думаю, что нашел обходной путь для этого, поскольку у меня была аналогичная проблема. В bugreport из ubuntu говорится, что библиотека javax.smartcardio ищет библиотеку ПК /SC в неправильном каталоге.
Указав путь к библиотеке ПК /SC на моей машине, как упоминается в bugreport, я получил ее работу.
Пути в bugreport неверны для меня, я на 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
Ответ 2
Я использую малину с версией debian arm
найдите местоположение libpcsclite сначала с помощью
$ ldd -r /usr/bin/pcsc_scan
а затем используйте расположение libpcsclite с помощью:
java -Dsun.security.smartcardio.library=/usr/lib/arm-linux-gnueabihf/libpcsclite.so.1
Ответ 3
Для всех, кто борется с этим на Ubuntu 14 с 64-битной машиной. Я нашел файл .so на самом деле расположен в следующем каталоге
/usr/lib/x86_64-linux-gnu/libpcsclite.so
Итак, запуск моего приложения с настройкой, как показано ниже, работал у меня
-Dsun.security.smartcardio.library =/USR/Library/x86_64-Linux-ГНУ/libpcsclite.so
Ответ 4
Вам нужно указать путь к 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
Ответ 5
Дополнение к решению с поставкой пути в качестве параметра следующим образом:
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"
Так как это обходной путь для ошибки, которая затрагивает всю систему, имеет смысл ИМХО применять это обходное решение в масштабах всей системы.
JAVA_OPTS имеет локальную область действия и должен оцениваться скриптами, запускающими ваш код; _JAVA_OPTIONS предполагается автоматически оценивать JRE.
Ответ 6
Еще один подход (мой любимый) - сделать некоторые символические ссылки.
Преимущество состоит в том, что он работает в общесистемной среде (нет аргументов 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
Примечание. Для этого, вероятно, потребуется доступ к суперпользователю.