- 作者: 塚越一雄
- 出版社/メーカー: 技術評論社
- 発売日: 2000/06
- メディア: 単行本
- 購入: 3人 クリック: 56回
- この商品を含むブログ (35件) を見る
前回はこちら
今回は、ioctl()の第2,第3引数の正体とioctlの使い方について説明します。
まずはioctl()の引数について。
第1引数は前回説明したとおり、制御するファイルディスクリプタです。
で、問題の第2引数は該当端末に対して要求する処理を示す整数値です。この指定可能な整数値はioctls.hに定義されています。内容はこんな↓感じ。
itotto@itotto > cat /usr/include/asm/ioctls.h #define TCGETS 0x5401 #define TCSETS 0x5402 ... itotto@itotto > wc -l /usr/include/asm/ioctls.h 83 /usr/include/asm/ioctls.h itotto@itotto >
ファイルの行数だけで83行ありますので、要求に使用する設定値も結構な数が定義されているようです。ひとまず今回は以下の二つだけを使用することにします。
記号定数 | 意味 |
---|---|
TCGETA | 端末の属性を取得する |
TCSETAF | 端末の属性を設定する |
最後に第3引数についてですが、これは端末の属性値を格納する構造体へのポインタを指定します。
itotto@itotto > cat /usr/include/asm/termios.h ... #define NCC 8 struct termio { unsigned short c_iflag ; /* input mode flags */ unsigned short c_oflag ; /* output mode flags */ unsigned short c_cflag ; /* control mode flags */ unsigned short c_lflag ; /* local mode flags */ unsigned short c_line ; /* line discripline */ unsigned short c_cc[NCC]; /* control characters */ } ... itotto@itotto >
各メンバーについての説明は以下のとおりです。
メンバー | 保持する値 | 説明 |
---|---|---|
c_iflag | 入力についてのフラグ | |
IGNBRK | 0000001 | 入力中のBREAK信号を無視. |
BRKINT | 0000002 | "IGNBRK" 設定時はBREAK信号に対して "SIGINT" を発生. 未設定時はBREAKを文字\0として読む. |
IGNPAR | 0000004 | フレーム,パリティエラーを無視. |
PARMRK | 0000010 | "IGNPAR" 未設定時はパリティ,フレームエラーの発生した文字の前に\377 \0.を付加. "IGNPAR" も "PARMRK" 共に未設定時は パリティ,フレームエラーの発生した文字を\0として読む. |
INPCK | 0000020 | 入力のパリティチェックを有効化. |
ISTRIP | 0000040 | ビット目を落とす. |
INLCR | 0000100 | 入力のNLをCRに置換. |
IGNCR | 0000200 | 入力のキャリッジリターン(以下CR)を無視. |
ICRNL | 0000400 | "IGNCR" が未設定時のみ,入力のCRを改行に置換. |
IUCLC | 0001000 | 入力の大文字を小文字に置換. |
IXON | 0002000 | 出力のXON/XOFFフロー制御を有効化. |
IXANY | 0004000 | 任意の文字を受信した時に再出力を実施. |
IXOFF | 0010000 | 入力のXON/XOFFフロー制御を有効化. |
IMAXBEL | 0020000 | 入力キューが一杯の時にベルを鳴らす. |
IUTF8 | 0040000 | 文字コードとしてUTF8を使用. |
メンバー | 保持する値 | 説明 |
---|---|---|
c_oflag | 出力についてのフラグ | |
OPOST | 0000001 | 実装に依存した出力処理を有効化. |
OLCUC | 0000002 | 出力時に小文字を大文字に変換. |
ONLCR | 0000004 | 出力のNLをCR-NLに置換. |
OCRNL | 0000010 | 出力のCRをNLに置換. |
ONOCR | 0000020 | 0桁目でCRを出力しない. |
ONLRET | 0000040 | CRを出力しない. |
OFILL | 0000100 | 転送時間を遅らせるのではなく、補填文字(fill character)を送信. |
OFDEL | 0000200 | 補填文字としてASCII DELを送信する (OFDEL未設定時はASCII NUL) |
NLDLY | 0000400 | 改行の遅延を設定. (設定値は "NL0"[遅延なし] および "NL1") |
NL0 | 0000000 | NLDLYの設定値 |
NL1 | 0000400 | 〃 |
CRDLY | 0003000 | CRの遅延を設定. (設定値は "CR0"[遅延なし], "CR1", "CR2", "CR3") |
CR0 | 0000000 | CRDLYの設定値 |
CR1 | 0001000 | 〃 |
CR2 | 0002000 | 〃 |
CR3 | 0003000 | 〃 |
TABDLY | 0014000 | 水平タブの遅延を設定.(設定値は "TAB0"[遅延なし], "TAB1", "TAB2", "TAB3", "XTABS") "XTABS" の値はタブをスペース何個に変換するかを示す(タブは8桁毎に止まる) |
TAB0 | 0000000 | TABDLYの設定値 |
TAB1 | 0004000 | 〃 |
TAB2 | 0010000 | 〃 |
TAB3 | 0014000 | 〃 |
XTABS | 0014000 | 〃 |
BSDLY | 0020000 | 後退の遅延を設定. (設定値は "BS0"[遅延なし]あるいは "BS1") |
BS0 | 0000000 | BSDLYの設定値 |
BS1 | 0020000 | 〃 |
VTDLY | 0040000 | 垂直タブの遅延を設定. (設定値は "VT0P"[遅延なし]あるいは "VT1") |
VT0 | 0000000 | VTDLYの設定値 |
VT1 | 0040000 | 〃 |
FFDLY | 0100000 | ページ送りの遅延を設定. (設定値は "FF0"[遅延なし]あるいは "FF1") |
FF0 | 0000000 | FFDLYの設定値 |
FF1 | 0100000 | 〃 |
メンバー | 保持する値 | 説明 |
---|---|---|
c_cflag | 通信プロトコルについてのフラグ | |
CBAUD | 0010017 | 不明 |
B0 | 0000000 | CIBAUDの設定値(多分) |
B50 | 0000001 | 〃 |
B75 | 0000002 | 〃 |
B110 | 0000003 | 〃 |
B134 | 0000004 | 〃 |
B150 | 0000005 | 〃 |
B200 | 0000006 | 〃 |
B300 | 0000007 | 〃 |
B600 | 0000010 | 〃 |
B1200 | 0000011 | 〃 |
B1800 | 0000012 | 〃 |
B2400 | 0000013 | 〃 |
B4800 | 0000014 | 〃 |
B9600 | 0000015 | 〃 |
B19200 | 0000016 | 〃 |
B38400 | 0000017 | 〃 |
EXTA | B19200 | 不明 |
EXTB | B38400 | 不明 |
CSIZE | 0000060 | 文字サイズを設定. (設定値は "CS5", "CS6", "CS7", "CS8") |
CS5 | 0000000 | CSIZEの設定値 |
CS6 | 0000020 | 〃 |
CS7 | 0000040 | 〃 |
CS8 | 0000060 | 〃 |
CSTOPB | 0000100 | 1ストップビットではなく,2ストップビットに設定. |
CREAD | 0000200 | 受信を有効化. |
PARENB | 0000400 | 出力にパリティを付加し,入力のパリティチェックを実施. |
PARODD | 0001000 | 入力および出力を奇数パリティチェック. |
HUPCL | 0002000 | 最終プロセスがDeviceをCloseした後,モデムの制御線をlowにする(切断) |
CLOCAL | 0004000 | モデムの制御線を無視. |
CBAUDEX | 0010000 | 不明 |
B57600 | 0010001 | 不明 |
B115200 | 0010002 | 不明 |
B230400 | 0010003 | 不明 |
B460800 | 0010004 | 不明 |
B500000 | 0010005 | 不明 |
B576000 | 0010006 | 不明 |
B921600 | 0010007 | 不明 |
B1000000 | 0010010 | 不明 |
B1152000 | 0010011 | 不明 |
B1500000 | 0010012 | 不明 |
B2000000 | 0010013 | 不明 |
B2500000 | 0010014 | 不明 |
B3000000 | 0010015 | 不明 |
B3500000 | 0010016 | 不明 |
B4000000 | 0010017 | 不明 |
CIBAUD | 002003600000 | 入力速度を制御 |
CMSPAR | 010000000000 | 不明 |
CRTSCTS | 020000000000 | フロー制御を実施 |
メンバー | 保持する値 | 説明 |
---|---|---|
c_lflag | 文字を出力する前のローカル処理についてのフラグ | |
ISIG | 0000001 | INTR, QUIT, SUSP, DSUSP の文字受信時に対応するシグナルを発生. |
ICANON | 0000002 | canonicalモードを有効化. (特殊キャラクタ EOF, EOL, EOL2, ERASE, KILL, REPRINT, STATUS, WERASE およびラインバッファが有効化される) |
XCASE | 0000004 | "ICANON" 設定時,端末は大文字のみが有効となる. 入力された文字は\が付いた文字を除いて小文字に変換. 出力時は大文字の前に\が付き,小文字は大文字に変換. |
ECHO | 0000010 | 入力キャラクタのエコーバック有効化. |
ECHOE | 0000020 | "ICANON" 設定時,ERASE 文字は前の文字を削除し,WERASE 文字は前の単語を削除. |
ECHOK | 0000040 | "ICANON" 設定時,KILL 文字は現在の行を削除. |
ECHONL | 0000100 | "ICANON" 設定時,ECHO が設定されていなくても NL 文字をエコー |
NOFLSH | 0000200 | "SIGINT", "SIGQUIT" シグナル発生時の入力および出力キューのフラッシュを無効化. "SIGSUSP" シグナル発生時の入力キューのフラッシュを無効化. |
TOSTOP | 0000400 | バックグラウンドプロセスのプロセスグループで,制御端末へ文字を出力しようとしているプロセスに対して "SIGTTOU" シグナルを送信. |
ECHOCTL | 0001000 | "ECHO" 設定時,TAB, NL, START, STOP の ASCII 制御文字が ^X としてエコー. Xは制御文字に対して ASCII コードで0x10大きな文字を表示 [例] 文字 0x28 (BS) は ^H とエコーする. |
ECHOPRT | 0002000 | "ICANON" および "IECHO" 設定時,削除された文字も表示. |
ECHOKE | 0004000 | "ICANON" 設定時, KILL が行の各文字を消去する代わりにエコーされる. "ECHOE" および "ECHOPRT" を指定することと等価. |
FLUSHO | 0010000 | 出力をフラッシュ. (DISCARD 文字を入力することで切替え可能) |
PENDIN | 0040000 | 次の文字を読み,入力キュー中の全文字を再表示. |
IEXTEN | 0100000 | 実装依存の入力処理を有効化. |
メンバー | 保持する値 | 説明 |
---|---|---|
c_cc[NCC] | 制御文字の配列 | |
VINTR | 0 | INTR 文字 |
VQUIT | 1 | QUIT 文字 |
VERASE | 2 | ERASE 文字 |
VKILL | 3 | KILL 文字 |
VEOF | 4 | EOF 文字 |
VTIME | 5 | TIME 値(キー入力を受け付ける時間(1/10[sec]) |
VMIN | 6 | バッファをフラッシュするデータ単位数 |
VSWTC | 7 | 不明 |
VSTART | 8 | START 文字 |
VSTOP | 9 | STOP 文字 |
VSUSP | 10 | SUSP 文字 |
VEOL | 11 | EOL 文字 |
VREPRINT | 12 | 不明 |
VDISCARD | 13 | 不明 |
VWERASE | 14 | WERASE 文字 |
VLNEXT | 15 | LNEXT 文字 |
VEOL2 | 16 | EOL2 文字 |
c_lineについては調べてみたもののよく分からなかったのでとりあえずここには載せません。あといくつか分からないフラグもあったので、それは不明としておきました。
以上がioctl()の引数です。この3つの引数を使用して端末制御を行います。
端末のエコーを止めてみる
sshなどで端末へ接続した時に、キーボードで入力した文字がそのままディスプレイに表示されます。このことを端末のエコーと呼びます。当たり前の動作なので、常時エコーしているのかと思いきや一部そのエコーが止まるときがあります。例えばパスワードを入力する時などです。それがどのように実現されているのか試してみます。
1 #include <sys/ioctl.h> 2 #include <asm/termbits.h> 3 #include <stdio.h> 4 5 int main() 6 { 7 char buff[BUFSIZ]; 8 struct termio tm, tm_save; 9 10 // 現在の設定を取得 // 11 ioctl(fileno(stdin), TCGETA, &tm); 12 13 // 現在の設定を一時保存 // 14 tm_save = tm; 15 16 // ECHOを止める // 17 tm.c_lflag &= ~ECHO; 18 19 // 改行だけはエコーする // 20 tm.c_lflag |= ECHONL; 21 22 ioctl(fileno(stdin), TCSETAF, &tm); 23 24 printf("パスワード?"); 25 fgets(buff, BUFSIZ, stdin); 26 buff[strlen(buff) - 1] = '\0'; 27 28 printf("パスワードは %s です\n", buff); 29 30 // 元に戻す // 31 ioctl(fileno(stdin), TCSETAF, &tm_save); 32 33 return 0; 34 }
ioctl()で現在の設定を取得し、その一部(今回はc_lflagのECHO,ECHONLフラグ)を変更して設定しなおしています。変更の方法にはビット演算を使っているので、その部分が分からない場合はCの参考書を読んでみてください。
それで、最初にこのテストプログラムを作ったときに2点はまりました。
-
- 標準入力に対するエコーがなくなってしまった
- ECHO,ECHONLがundeclaredと言われる
1.についてはちなみに30行目にあるように、プログラム実行時の設定値を元に戻さないでいると、ログオフするまでずっとエコーされないという悲しい状態に陥ることが分かりました。なので必ず最後には戻すように気をつけましょう。
2.については書籍ではsys/ioctl.hをincludeすれば大丈夫と書いてありましたが、最近変わったのかこれではダメなようです。asm/termbits.hにc_lflagの定数定義があったのを覚えてたので(上の表を作るときに見つけました)これをincludeして解消しました。これについてはもう少し調べてみます。
プログラムを実行した場合はこんな感じの動きになります。
[itotto@itotto ]$ gcc -o no_echo no_echo.c [itotto@itotto ]$ ./no_echo パスワード? ← HOGEHOGE と入力しても表示なし パスワードは HOGEHOGE です [itotto@itotto ]$
本当はCOOKEDモードとRAWモードまで説明したかったのですが、長くなったのでそれはまた次回。
(参考ページ)