24

次のコードでjavax.smartcardioAPIを使用してスマートカード端末をロードしようとしています。

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では動作しません。Ubuntu12.0464ビットを使用しています。

次のコマンドを使用して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 <ludovic.rousseau@free.fr>
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>
  ...

したがって、すべてが正常に見えますが、smartcardioは機能しません。OracleとOpenJDK1.7.0_05、32ビットと64ビットの両方で試しています。

コードは、Ubuntu 32ビット環境でOpenJDK(ただし、Oracle JDKではなく、理由はわかりません)で正常に実行されます。したがって、JavaからPC/SCライブラリへの64ビットブリッジに問題があると思います。

何か案は?

ありがとう。

4

7 に答える 7

38

同様の問題が発生したため、この回避策を見つけたと思います。ubuntuからのバグレポートでは、javax.smartcardioライブラリが間違ったディレクトリでPC/SCライブラリを検索すると書かれています。

バグレポートに記載されているように、マシン上のPC / SCライブラリへのパスを指定することで、それを機能させることができました。

バグレポートのパスは私にとって間違っています。私は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
于 2012-09-12T10:55:55.427 に答える
8

私はDebianアームバージョンでラズベリーを使用しています

最初にlibpcscliteの場所を見つけます:

$ ldd -r /usr/bin/pcsc_scan

次に、libpcscliteの場所を次のように使用します。

java -Dsun.security.smartcardio.library=/usr/lib/arm-linux-gnueabihf/libpcsclite.so.1
于 2013-12-30T03:53:43.453 に答える
4

64ビットマシンを搭載したUbuntu14でこれに苦労している他の人のために。.soファイルは実際には次のディレクトリにあります

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

したがって、以下の設定でアプリを実行すると、うまくいきました

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

于 2015-03-03T12:28:39.570 に答える
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へのパスを含めずに、通常どおりコードを実行できます。

于 2016-06-14T05:24:50.807 に答える
2

次のようなパラメータとしてパスを指定することで、ソリューションに追加します。

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"

これはシステム全体に影響を与えるバグの回避策であるため、IMHOがこの回避策をシステム全体にも適用することは理にかなっています。

JAVA_OPTSにはローカルスコープがあり、コードを実行するスクリプトによって評価される必要があります。_JAVA_OPTIONSは、JREによって自動的に評価されることになっています。

于 2015-07-10T12:47:45.103 に答える
1

さらに別のアプローチ(私のお気に入り)は、いくつかのシンボリックリンクを作成することです。

システム全体で機能するという利点があります(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

注:これには、おそらくスーパーユーザーアクセスが必要になります。

于 2015-09-24T19:24:13.850 に答える
1

@AshanPereraの回答を補完すると、毎回検索が遅くなることがあるため、最初に検索すると、場所がファイルに保存され、それ以降は次のように読み取られます。

        try {

        String filename = "libpcsclite.location"; 
        File propertyFile = new File(filename);
        if(propertyFile.createNewFile()) 
        {   
            String commandWithArguments[] = { "find", "/usr", "/lib", "-name","libpcsclite.so.1" };
            Process searchProcess = Runtime.getRuntime().exec(commandWithArguments);
            BufferedReader searchReader = new BufferedReader(new InputStreamReader(searchProcess.getInputStream()));
            String propertyValue;
            while ( (propertyValue = searchReader.readLine()) != null && !propertyValue.equals("")) 
            {
                if (propertyValue.contains("libpcsclite.so.1")) {
                    BufferedWriter propertyWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(propertyFile)));
                    propertyWriter.write(propertyValue);
                    propertyWriter.close();
                    System.setProperty("sun.security.smartcardio.library",propertyValue);
                    break;
                }
            }
            searchProcess.waitFor();
        }
        else 
        {  
            BufferedReader propertyReader = new BufferedReader(new InputStreamReader(new FileInputStream(propertyFile)));                 
            String propertyValue = propertyReader.readLine(); 
            System.setProperty("sun.security.smartcardio.library",propertyValue);       
        }
    } catch (Exception e) {

        e.printStackTrace();
    }
于 2018-10-15T20:52:56.717 に答える