Friday, 9 July 2010

Variable Length DAT read on Linux



まぁ、HP DAT72 のデータは読めたので問題ないんですけどね。

http://bit.ly/9N0Nq6

RDHL でも同じ問題ではまっている人はいるらしい。

  mt -f /dev/nst0 setblk 0

で、普通は問題なく読める。でも、cat とか od だと、

  cannot allocate memory

と言って来る。

dd で指定した block size が合っていれば。合ってなければ、block size が小さい場合は、

  st0: Failed to read 3072 bytes block with 512 byte transfer.

と言う。ただし、大きめのblockを指定するすると、黙って zero fill する。これは、たぶん、dd の仕様だな。

このメッセージは、dmesg でしか読めない。Knoppix のsystem log はどこに出るんだ? /var/log の下にはないらしい。でも、このメッセージを見れば block size はわかる。


で、fix block size だと、dd で正しい block size を指定すれば終り。

問題は、variable length で、record 毎に block size が変わる場合。read で大きめなbuffer を用意すれば良いかと言うと、そうでもないらしい。そもそも、 cannot allocate memory って一体、どこで誰が allocate しているわけ?

man stとか man mt とかするのだがどうしても、「次のblock size を知る方法」がわからない。mt -f /dev/nst0 status ぐらいではダメなようです。つうか、setblk の値しか出ないじゃん。

なので、以下のような script を書いて読み込みました。

  #!/usr/bin//perl

  $TAPE="/dev/nst0";
  $CMD0=" ssh myname@myhost dd of=/Users/home/data.tgz";

  open(HOGE, ">/tmp/aho");
  select(HOGE);
  $| = 0;

  select(STDOUT);

  @blocks=();

  $run = 1;
  system("mt -f $TAPE rewind");
  system("mt -f $TAPE setblk 0");
  while( $run ) {


      system("dd if=$TAPE bs=512 count=1 ");

      $last = `dmesg | tail -1`;
      $last =~/^(.*) st0: Failed to read ([0-9]+) byte block with 512 byte transfer./;

      $key = $1;
      $block = $2;
      if (! defined $bb{$key}   ) {
        print STDERR "block ",$count++," $1 $2\n";
        $bb{$key} = $block;
        push(@blocks, $block);
        system("mt -f $TAPE bsr 1");
        system("dd if=$TAPE bs=$block count=1 ");
        print HOGE $_,"\n";
      } else {
        $run = 0;
      }
  }

やってられませんですよ。

No comments: