ZFS の zpool status で出てくるデバイス名が変になっちゃったときの対処法

確認したのは、FreeBSD なので、FreeNAS とかでも同じはず。 (完全に自分用メモ…)

USB メモリなどの別のディスク(インストーラでOK)から起動し single user mode に入って

# zpool import -d /dev/gpt/ -N -f zroot
# zpool export zroot

を実行する。 おわり。

zfs は成功した最後の組み合わせをそれぞれのディスクに覚えているので、時々めんどくさい…。

真・標準出力に栓をする

sleep(1)で標準出力に栓をする | 上田ブログ

うんうん。標準出力に栓をしたいことって、ありますよね!*1

記事で言及されているソートの結果やyesコマンドのように ある程度データが大きいときは大丈夫なのですが、残念ながら小さいデータの場合には期待通りに動きません。

通常、データを別のプロセスにパイプで渡すと、そのままでは一旦バッファに吸収されてしまいます。
実例を見るのが早いです。

#include <stdio.h>
#include <fcntl.h>

main()
{
        int fd;

        fd = open("test1.dat", O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (fd < 0) {
                return -1;
        }
        close(fd);

        printf("Hello\n");

        fd = open("test2.dat", O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (fd < 0) {
                return -1;
        }
        close(fd);

        return 0;
}

副作用を起こすために、それぞれの段階でファイルを生成しています。


まずは sleep で実行してみます。

% gcc test.c
% ls
a.out  test.c
% ./a.out | sleep 10000 &    # 実行
[1] 14439 3005
% ls                         # ↓ この時点で既に test2.dat まで生成されてしまってる
a.out     test.c    test1.dat test2.dat
% ps -p 14439 -p 3005        # ↓ sleep は居るけど、a.out は居ない
 PID TTY   STAT    TIME COMMAND
3005 pts/4 S    0:00.00 sleep 10000
% fg
./a.out | sleep 10000
^C
% ls
a.out     test.c    test1.dat test2.dat
%

確かに sleep は実行されていますが、a.out は先に終了しており、test2.dat が生成されてしまっています。

この現象は、printf によるパイプへの書き込みが、パイプのバッファサイズ(OSや設定に依存/通常4KB程度)以下の場合に起こります。 逆に printf のところで 4KB以上の書き込みを行うと、期待通りプロセスがブロックします。


これを、どんなデータ量でも printf のところで確実に停止させるには、次のテクニックが手軽で便利です。

% stty tostop                # ラインディシプリンの設定
% rm test[12].dat
% ls
a.out  test.c
% ./a.out &                  # バックグラウンドで実行
[1] 15519
% ps -p 15519
  PID TTY   STAT    TIME COMMAND
15519 pts/4 T    0:00.00 ./a.out
[1]  + Stopped (tty output)   ./a.out
% ls                         # ↓ test1.dat のところまで実行されてる
a.out     test.c    test1.dat
% fg                         # 再開
./a.out
Hello
% ls                         # ↓ test2.dat が出てくる
a.out     test.c    test1.dat test2.dat
%

上記のように stty tostop を発行してから、プロセスをバックグラウンドで実行するだけです。

標準出力先は通常の tty のままですが、ラインディシプリンによって最初の書き込みの直前に確実にプロセスを停止できます。
(よって tty上でしか効力を発揮できないため、スクリプトなどからは使えません…)


当たり前ですが、tostop が設定されていない通常の場合だと、以下のようになります。

% stty -tostop
% rm test[12].dat
% ls
a.out  test.c
% ./a.out &
[1] 19645
% Hello           # ← 単なるバックグラウンド実行なので結果がすぐ出る
ps -p 19645       # ↓ プロセスも居なくなってる
PID TTY STAT TIME COMMAND
[1]    Done                   ./a.out
% ls
a.out     test.c    test1.dat test2.dat
%

本当にニッチな技術ですが、覚えておくと何か*2に使えるかもしれません。

*1:gdb で break point しかけてもいいけど、めんどくさかったり gdb 無かったりするじゃない?

*2:まぁCTFぐらいしか思いつかないけど

Oracle 8i で、無理やり JA16EUCTILDE (や JA16SJISTILDE) を使う方法

Oracle Database と戯れていると、チルダが文字化けするときがあります。 (Oracle に限らないけど)

例えば接続先のサーバのデータベース自体のキャラクタセットが JA16EUCTILDE とかになっているのに、クライアント側からは JA16EUC で接続する場合です。

こんな状況は、なにも考えずにサーバ側だけ Oracle 8i から Oracle 10g とかにアップグレードしてしまうと発生します。
(たぶん。詳しく知らない。誰だよ、やったやつ…)

こういう時はクライアント側でも同じ JA16EUCTILDE を使う必要があるのですが、残念ながら Oracle 8i には JA16EUCTILDE (や JA16SJISTILDE) がありません。
文字化けを解消したかったら、クライアントのバージョンを(9i以降に)上げるしか無いのです。

しかし現実には、クライアントのバージョンを上げることができませんでした…。
(データベース側のキャラクタセットを変更/調整するのは、もっとできない)

…そんな状況で見つけた黒魔術です。

ここでの環境は Oracle 8.1.7 です。

lx0boot.nlt

VERSION=2.1.0.0.0

CHARACTER_SET

"JA16EUCTILDE"  837


lx20345.nlt

VERSION = 2.1.0.0.0

DEFINE character_set

  name = "JA16EUCTILDE"
  id = 837
  base_char_set = 830

  character_data = {
     0xa1c1 : 0xff5e,
  }

ENDDEFINE character_set

上記のファイルを作業ディレクトリに用意します。

さらに ${ORA_NLS33} にある lx0boot.nlb lx1boot.nlb lx2033e.nlb lx6033e.nlb を作業ディレクトリにコピーしてきます。
(逆に *.nlt を ${ORA_NLS33} に置いて、直接書き換えることもできるけど、怖いので…)

そしておもむろに以下のコマンドを実行します。

% lxinst oranls=. sysdir=. destdir=.

NLS Data Installation Utility: Version 3.4.1.0.0 - Production

Copyright (c) Oracle Corporation 1993, 1995, 1996, 1997, 1999, 2000. All rights reserved.

CORE    8.1.7.0.0       Production


Generating binary object and installation boot files...
LXI-WARN-00510: In lx20345.nlt at line 10, unicode 0xff5e out of private use range
LXI-WARN-00512: In lx20345.nlt at line 10, character 0xa1c1 is remapped

Merging installation and system boot files...


NLSRTL Object installation successfully completed

そしてできあがった lx0boot.nlb lx1boot.nlb lx20345.nlb lx60345.nlb を ${ORA_NLS33} に書き戻すと NLS_LANG で JA16EUCTILDE が使えるようになります。
(lx?boot.nlb は上書きされるので、バックアップはとっておきましょう)

同様にして JA16SJISTILDE も作れると思います。

自己責任でどうぞ。

vim でタブ文字と改行文字を見やすくする方法 (Unicode編)

簡単なんだけど、よく忘れるのでメモ。

f:id:kikuchan98:20140604024905p:plain

まず、端末が UTF-8 を表示できることが前提。

~/.vimrc に以下のように記載。

set encoding=utf-8
scriptencoding utf-8
set listchars=tab:→\ ,eol:↲
set list

" お好みに応じて、適切な場所で色設定
hi SpecialKey ctermfg=237 guifg=#3a3a3a
hi NonText ctermfg=66 guifg=#5f8787

「→」と「↲」は、INSERTモード中にそれぞれ <C-v>uffeb および <C-v>u21b2 で入力できる。

これの難点は、コピペするときに改行文字とかが混入すること、かな。
コピーする前に :set nolist で消せば、だいじょーぶ。

ちなみに EUC-JP に(そんなもの無いけど無理やり)外字として「→」と「↲」を登録しておいて、iconv 自体を改造して UTF-8 とのマッピングを定義してあげれば set termencoding=euc-jp でも動くよ。