ラジコの録音、東京の放送を取得する一案(3 トークンだけ取得

トークンを取得するだけのスクリプトを作ります。

最終的にちゃんと取得できているかを確認するためのrtmpdumpコマンドをエコー(表示)しています。

#!/bin/sh

# TBS:TBSラジオ
# QRR:文化放送
# LFR:ニッポン放送
# NSB:ラジオNIKKEI
# INT:INTER FM
# FMT:TOKYO FM
# FMJ:J-WAVE
# JORF:ラジオ日本
# BAYFM78:bayfm78
# NACK5:NACK5
# YFM:FMヨコハマ

if [ $# -eq 1 ]; then
  CHANNEL=$1
else
  echo "usage : $0 CHANNEL"
  exit 1
fi

CHANNEL=$1

RTMPDUMP=/usr/local/bin/rtmpdump
FFMPEG=/usr/bin/ffmpeg
MP3PATH=/home/mlin/html/mp3/

OUTFILEBASEPATH=./
OUTFILENAME=${OUTFILEBASEPATH}/`date +%Y-%m-%d`
FLVFILEEXT=".flv"
AACFILEEXT=".aac"
MP3FILEEXT=".mp3"

MARGINTIMEMIN=1
# RECTIME=`expr ${RECTIMEMIN} \* 60 + ${MARGINTIMEMIN} \* 2 \* 30`

# 30sec wait
# echo "===== `date` Wait 30sec. ====="
# for f1 in 0
# do
  # for f2 in 9 8 7 6 5 4 3 2 1 0
  # do
    # echo -n "$f1$f2\r"
    # sleep 1
  # done
# done

#開始時刻
START=`date +%s` 

cd ${OUTFILEBASEPATH}

playerurl=http://radiko.jp/player/swf/player_3.0.0.01.swf
playerfile=./player.swf
keyfile=./authkey.png

#
# get player
#
if [ ! -f $playerfile ]; then
  wget -q -O $playerfile $playerurl

  if [ $? -ne 0 ]; then
    echo "failed get player"
    exit 1
  fi
fi

#
# get keydata (need swftools)
#
if [ ! -f $keyfile ]; then
  swfextract -b 14 $playerfile -o $keyfile

  if [ ! -f $keyfile ]; then
    echo "failed get keydata"
    exit 1
  fi
fi

if [ -f auth1_fms_${CHANNEL} ]; then
  rm -f auth1_fms_${CHANNEL}
fi

#
# access auth1_fms
#
for var in 3 5 7 9 10 0
do
  wget -q \
       --header="pragma: no-cache" \
       --header="X-Radiko-App: pc_1" \
       --header="X-Radiko-App-Version: 2.0.1" \
       --header="X-Radiko-User: test-stream" \
       --header="X-Radiko-Device: pc" \
       --post-data='\r\n' \
       --no-check-certificate \
       --save-headers \
       --tries=5 \
       --timeout=5 \
       -O auth1_fms_${CHANNEL} \
       https://radiko.jp/v2/api/auth1_fms

  if [ $? -ne 0 ]; then
    if [ $var -ne 0 ]; then
      # echo "failed auth1 process [$var sec sleep...retry]"
      sleep $var
    else
      # echo "[[[[ Failed auth1 process --- `date` --- ]]]]"
      exit;
    fi
  else
    # echo "sucsess auth1 process"
    break;
  fi
done
#
# get partial key
#
authtoken=`cat auth1_fms_${CHANNEL} | perl -ne 'print $1 if(/x-radiko-authtoken: ([\w-]+)/i)'`
offset=`cat auth1_fms_${CHANNEL} | perl -ne 'print $1 if(/x-radiko-keyoffset: (\d+)/i)'`
length=`cat auth1_fms_${CHANNEL} | perl -ne 'print $1 if(/x-radiko-keylength: (\d+)/i)'`

partialkey=`dd if=$keyfile bs=1 skip=${offset} count=${length} 2> /dev/null | base64`

# echo "authtoken: ${authtoken} \noffset: ${offset} length: ${length} \npartialkey: $partialkey"
echo ${authtoken}

rm -f auth1_fms_${CHANNEL}

if [ -f auth2_fms_${CHANNEL} ]; then
  rm -f auth2_fms_${CHANNEL}
fi

#
# access auth2_fms
#
for var in 3 5 7 9 10 0
do
  wget -q \
       --header="pragma: no-cache" \
       --header="X-Radiko-App: pc_1" \
       --header="X-Radiko-App-Version: 2.0.1" \
       --header="X-Radiko-User: test-stream" \
       --header="X-Radiko-Device: pc" \
       --header="X-Radiko-Authtoken: ${authtoken}" \
       --header="X-Radiko-Partialkey: ${partialkey}" \
       --post-data='\r\n' \
       --no-check-certificate \
       --tries=5 \
       --timeout=5 \
       -O auth2_fms_${CHANNEL} \
       https://radiko.jp/v2/api/auth2_fms

  if [ $? -ne 0 -o ! -f auth2_fms_${CHANNEL} ]; then
    if [ $var -ne 0 ]; then
      echo "failed auth2 process [$var sec sleep...retry]"
      sleep $var
    else
      echo "[[[[ Failed auth2 process --- `date` --- ]]]]"
      exit;
    fi
  else
    echo "sucsess auth2 process"
    break;
  fi
done

echo "authentication success"

areaid=`cat auth2_fms_${CHANNEL} | perl -ne 'print $1 if(/^([^,]+),/i)'`
echo "areaid: $areaid"

rm -f auth2_fms_${CHANNEL}

echo rtmpdump -v \
              -r "rtmpe://f-radiko.smartstream.ne.jp" \
              --playpath "simul-stream.stream" \
              --app "${CHANNEL}/_definst_" \
              -W $playerurl \
              -C S:"" -C S:"" -C S:"" -C S:$authtoken \
              --live \
              --flv ./test2.flv \
              --stop 30
exit

少し工夫した部分は
  for var in 3 5 7 9 10 0
の部分ですね。
トークンを得る際にエラーが出る場合を考慮して5回やり直します。
3.5.7と数値が書いてあるのは、その秒数スリープさせるためです、
連続でエラーになった場合には徐々に待ち時間を長くしています。
最後の0で諦める、と言った形です。

ラジコの録音、東京の放送を取得する一案(2 サーバークライアントの基本

ソケット通信を試します。
結構難しいのですが、以下のサンプルを使ってなんとかします。

要は、クライアントからチャンネル情報を送って、
サーバーからトークンを返すだけ、なのでこれで良いのです。

サーバー

さくらインターネットの方でサーバーを起動させます。

 

#!/usr/bin/perl

use strict;
use warnings;
use Socket;
use Fcntl qw(:flock);

# 2. 受付用ソケット情報の作成
my $local_port = 9000;

#ロック
open  LOCK , "+>" , "./serverlock.${local_port}";
if ( flock LOCK ,LOCK_EX|LOCK_NB ){
    print "OK LOCK!\n";
}else{
    print "NG LOCK!$!\n";
    exit ;
}

# サーバ

# 1. 受付用ソケットの作成

my $sock_receive;
socket($sock_receive, PF_INET, SOCK_STREAM, getprotobyname( 'tcp' ))
  or die "Cannot create socket: $!";


my $pack_addr = sockaddr_in($local_port, INADDR_ANY);

# 3. 受付用ソケットと受付用ソケット情報を結びつける
bind($sock_receive, $pack_addr)
  or die "Cannot bind: $!";

# 4. 接続を受け付ける準備をする。
listen($sock_receive, SOMAXCONN)
  or die "Cannot listen: $!";

# 5. 接続を受け付けて応答する。
my $sock_client; # クライアントとの通信用のソケット

while (accept( $sock_client, $sock_receive )) {
  my $content;
  
  # クライアントからのデータの読み込み
  while (my $line = <$sock_client>) {
    $content .= $line;
  }

  my $ret="Server."
  
  # クライアントへのデータの書き込み
  print $sock_client "$ret";
  close $sock_client;
}

$contentという変数にクライアントからのデータを取得できます。
クライアントにデータを戻すには、
print $sock_client “$ret”;
で行っています。この例は単に「Server.」と返しています。

クライアント

ラズパイからクライアントを起動します。
サーバーに繋いでサーバーからデータを受け取ります。

#!/usr/bin/perl

use strict;
use Socket;

my $CH="";
if (@ARGV == 1){
    $CH=$ARGV[0];
}else{
    print "usage : ./$0 [CHANNEL]\n";
    exit 1;
}

# クライアント
# 1. ソケットの作成
my $sock;
socket($sock, PF_INET, SOCK_STREAM, getprotobyname('tcp' ))
  or die "Cannot create socket: $!";

# 2. ソケット情報の作成

# 接続先のホスト名
my $remote_host = 'サーバーのドメイン';
my $packed_remote_host = inet_aton($remote_host)
  or die "Cannot pack $remote_host: $!";

# 接続先のポート番号
my $remote_port = 9000;

# ホスト名とポート番号をパック
my $sock_addr = sockaddr_in($remote_port, $packed_remote_host)
  or die "Cannot pack $remote_host:$remote_port: $!";

# 3. ソケットを使って接続
connect($sock, $sock_addr)
  or die "Cannot connect $remote_host:$remote_port: $!";

# 4. データの書き込み
# 書き込みバッファリングをしない。
my $old_handle = select $sock;
$| = 1; 
select $old_handle;

print $sock "Hello";

# 書き込みを終了する
shutdown $sock, 1;

# 5. データの読み込み
my $cnt=0;
while (my $line = <$sock>) {
  print "$cnt $line";
  $cnt++;
}

# 6. ソケットを閉じる
close $sock;

サーバーにデータを送るには
print $sock “Hello”;
でやっています。
そのあとの
print “$cnt $line”;
でサーバーからの返答を受け取るというわけです。

ラジコの録音、東京の放送を取得する一案(1

そもそも、radikoの録音はどうやっているのでしょうか。

まずはトークンを取得します。

TBSラジオの例です。

wget -q '--header=pragma: no-cache' '--header=X-Radiko-App: pc_1' \
'--header=X-Radiko-App-Version: 2.0.1' '--header=X-Radiko-User: test-stream' \
'--header=X-Radiko-Device: pc' '--post-data=\r\n' \
--no-check-certificate --save-headers --tries=5 --timeout=5 \
-O auth1_fms https://radiko.jp/v2/api/auth1_fms

これでトークンがとれます。

トークン

cat auth1_fms | perl -ne 'print $1 if(/x-radiko-authtoken: ([\w-]+)/i)'

パーティカルキー

# offset
cat auth1_fms_${OUTFILEPREFIX}_${CHANNEL} | perl -ne 'print $1 if(/x-radiko-keyoffset: (\d+)
/i)'
# length
cat auth1_fms_${OUTFILEPREFIX}_${CHANNEL} | perl -ne 'print $1 if(/x-radiko-keylength: (\d+)
/i)'

取得したoffsetとlengthを使って取得します。

dd if=$keyfile bs=1 skip=[offset] count=[length] 2> /dev/null | base64

例)トークン S:wdaDhu6evQheSnXIM8vbGA
パーティカルキー cHHB6YxRZrVhZMRASY1J4w==

ところが、このトークンはまだ使えません。

更に認証を通します。

取得したトークンとパーティカルキーを使います。

wget -q '--header=pragma: no-cache' '--header=X-Radiko-App: pc_1' \
'--header=X-Radiko-App-Version: 2.0.1' '--header=X-Radiko-User: test-stream' \
'--header=X-Radiko-Device: pc' \
'--header=X-Radiko-Authtoken: wdaDhu6evQheSnXIM8vbGA' \
'--header=X-Radiko-Partialkey: cHHB6YxRZrVhZMRASY1J4w==' \
'--post-data=\r\n' --no-check-certificate --tries=5 \
--timeout=5 -O auth2_fms https://radiko.jp/v2/api/auth2_fms

こうして取得したトークンを使えばよいです。

rtmpdump -v -r rtmpe://f-radiko.smartstream.ne.jp --playpath simul-stream.stream \
--app TBS/_definst_ -W http://radiko.jp/player/swf/player_3.0.0.01.swf \
-C S: -C S: -C S: -C S:wdaDhu6evQheSnXIM8vbGA --live \
--flv ./test.flv --stop 30

最後を少し変えれば、そのまま再生もできます。

rtmpdump -v -r rtmpe://f-radiko.smartstream.ne.jp --playpath simul-stream.stream \
--app TBS/_definst_ -W http://radiko.jp/player/swf/player_3.0.0.01.swf \
-C S: -C S: -C S: -C S:wdaDhu6evQheSnXIM8vbGA --live \
--flv - | mplayer -cache 500 -quiet -

mplayerが必要です。

ラジコの録音の件。東京の放送を取得する一案

ラジコの録音をDTIでやっていたのですが、どうにも不安定なので、ラズパイでやろうと思ったのですが、何故かうまくいきませんでした。
正確には数日はうまく行っていたのに突然接続不能となりました。
DTIは問題がないので、録音時代が不能になったわけではないみたい。
調べていくうちに、何故か我が家が”富山”と認識されていることがわかりました。
プロバイダをso-netのADSLからコミュファに変更したことが思いっきり影響してしまったようです。

申請して修正してもらってもいいのですが、また暫く経つと別の地域に変わってしまうので解決になりません。
いまは愛知と静岡を行ったり来たりしています。。。

これでは録音機としてまったく使えないので、対策を練りました。

VPNをつかって東京につなぐという方法もありますが、もっと手軽に何とかなる方法を考えました。
録音を開始するにははじめにトークンを取得して、ダウンロードを行います。
どうやらこのトークンを1度取得してしまえば、切断するまでは接続し続けられるようです。

とすれば、東京にサーバーが一つあって、トークンだけそこで取得できれば・・・。
DTIのserversmanが東京にありますので、取得はできそうです。
ただし、DTIはスペック不足なのか不安定です。
そこで、さくらインターネットです。私にはさくらインターネットのスタンダード契約が2つあります。
実は以前ラジコ録音ができないか試しましたが、残念ながら流石に無理でした。
原因はrtmpdumpのインストールが無理だったのです。
しかし、トークンだけなら可能でした。
ラズパイ→さくらインターネットにつなぐ→トークン取得
こんな感じです。
さくらインターネットはレンタルサーバーですので、httpのプロトコルを使っても簡単に取得できそうです。
が・・・、ちょっとそれだとつまらないので、ソケットを使ってみました。
バッチリ成功し、とても面白かったので、この手法を次から説明していこうと思います。

Google Play Musicのアップロード曲がダウンロード制限されるようになった

GooglePlayMusicを使っているでしょうか。
端末を意識することが不要な点が素晴らしいです。
iphoneで聞いたり、時にはタブレット(アンドロイド)でも聞けますし、
デスクトップPCでも、ノートPCでも何も気にせず、どこでも再生できます。
アップロード制限は5万曲で、困ることはなさそうです。

車で聞くためにはBluetoothでもいいのですが、
車のUSBに入れたいな・・・という場合も、簡単にダウンロードができるので、
ま、ここはちょっと不便ですが、あの曲はどこ行った?ということがないので、かなり便利に使っていました。

ダウンロード制限が・・・!

本日、あるアルバムの曲の音量が小さいような気がしたので、一度ダウンロードして調整しようと考えました。すると・・・

今までは出なかったこんな表示が・・・!

実は1回目はすぐに、今すぐダウンロード、を押してしまいました。
というわけで、あと1回、になっていますね。

1曲について2回まで、になってしまいました。何で2回・・・。しかも永遠に2回なのでしょうかね・・・?リセットされることはないのでしょうか。

Chrome版は制限がない?

上記のダイアログを見ますと、

「Chrome版 Google Play Musicを使用してダウンロードする場合は、この制限はありません。」

とあります。と言っても妙です。
すでにChrome版 Google Play Musicを使っているつもりなのですが・・・。

そこでこのリンクを押してみます。

リンクを押すと、いつものアプリストアが出て、アプリを追加します。

変だなあ。すでに追加してると思うのですけど・・・。

なにはともあれこんな表示が出ます。

わりかし待たされますが、ひたすら待ちます。

 

そうして、試しに2回3回ダウンロードを試しましたが・・・!OKのようです!

Chrome版 Google Play Musicを使えと言っていますが、
どうもバージョンアップしろってことみたいです。

2回以上試すとどうなる・・・?

一応拒否されるのを確認しようと思い試してみました。

IEで試すと・・・

一応先程の「あと1回です」の警告は出るのですが、
何度でもダウンロードできちゃいます・・・???

もしかしたら、制限機能をつけたばかりでうまく動作していないのかもしれませんね。

 

FreeNomのドメインが急に消えてた

ふとFreeNomで取得したドメインで運用していたサイトが突然接続できなくなりました。
ルーターの調子が悪いのかと思い再起動しても繋がらない・・・。
不審に思ってFreeNomを開いてみると、そのドメインが一覧からなくなっていました。

アクセスはしていたはずなので、なぜ消されたのか不明です。
ちなみに警告のメールは来ていませんでした。ドメイン名で検索すると取得した時のメールがでてきましたが。

ドメインは突然削除される

本当に何の前触れもなく消えました。
4/28に取得して、8/20に消されたようです。約4ヶ月?
自分のメモ的なサイトをワードプレスで作って使用していました。
なので、アクセスがまったくないということは断じてありません。
FreeNomは何の通知もなく突然消滅してしまうようです。
しかも、消えたドメインは2つです。
無料サービスとは言え、全くメールも来ていないことはちょっとショックでしたね。
更新通知は来たのに・・・。

でも、再取得が可能だった

突然ドメインを消して、再取得からはお金を取るのか・・・?と思っていましたが、
あっさり無料で再取得が可能でした。ここは意外でした。
念のためこの2つを再取得しておきました。
以前と同じように、電話番号も不要で取得できました。
そのうち電話番号は必要になるかもしれませんね。

規約はどうなってる?

21. 私のドメインが無効になることはありますか?

はい。無料ドメイン名を持つことはあなたに法的な登録者の権利を与えるものではありません。 1〜12ヶ月間、選択したドメイン名を使用することができます。 あなたが期限内にドメイン名を更新しない場合登録は解除されます。 各登録期間の最後の15日間に無料ドメインの無料更新ができます。 あなたのウェブサイトが長期間停止している場合や受け入れ難い内容、またはアップロードしていない場合、そのドメインはキャンセルされます。 その結果あなたのドメイン名は、無料または有料登録する他の登録者に対して自動的に利用可能になる可能性があります。

期限内に更新しない場合は解除、とありますが、期限内とはどのくらいなのでしょう?
長期間停止・・・そんなことないと思うんだけどな・・・。メモだけど。
アップロードしていない・・・これはない。

検索していたら「90日に25回のアクセス」というのがありました。
どうもFreenomではないようですが・・・。でもこれだって達成しているはずです。
毎日アクセスしていましたので・・・。

というわけで、時々Freenomのドメイン一覧は見たほうが良いみたいですね。
もちろんあんまり信頼しないことは絶対条件で、完全に消えちゃったらドメイン変えればいいか?くらいの使い方をおすすめします。

Hi8Pro のWindowsをクリエイターズアップデートするのに苦労した話

言わずと知れたHi8ProというChuwiのタブレットを持っています。
あんまり使っていないのですが、この度思い立ってクリエイターズアップデートを適用してみました。
というのも容量がかなり少なくて簡単には出来ないのですよ。

容量が足りないとアップデートできない

普通にアップデートしようとすると、

「8GB以上の空きが必要だよ!」

と無情なメッセージが出ます。
空き容量を増やす、って言う機能を進められるんですが、
単にホームディレクトリをSDメモリに移動できるだけ・・・。とても8GBなんて空きません。

そこで、メディアクリエイションツールを使ってUSBのアップデートドライブを作りました。

メディアクリエイションツールを使っても不可

32GBのSDカードを使ってつくりました。残容量はまだもりもりあります。
ところが、

  • Cドライブ・・・1GBくらい足んない
  • 他のドライブ・・・なし

のような画面が出てきます。
Cドライブはなんとか2.5GBくらい開けてます。それでもまだ足りないと。
そして、他のドライブと言うのは、アップデート作業領域のようで、10GB位欲しいと書いています。
あれ・・・?「メディアクリエイションツールの中身がら空きなんですけど・・・」

そうなんです。メディアクリエイションツールで作ったメモリがいくら空いていてもそこを作業領域として使ってくれないんです!!!これは糞仕様!!
しかも、外部記憶装置を使わない、を試しに選択してみると、もっとCドライブを開けろと・・・アホか!出来ないから困ってるのに!!!

結局Cドライブは一旦ハイバネートを切ることでなんとか通りました。

powercfg /hibanate off

これでメモリ2GB分空きます。これにてCドライブはOK!

後は外部記憶装置です。

そこで、たまたまこないだ買ったばかりの64GBのSDカード(ラズパイバックアップ済みだけど・・・)をフォーマットして、
これまたたまたまこないだ買ったOTG対応のTYPEC?microUSBの変換アダプタを使って、
更にそこからOTGのUSBアダプタ、USBアダプタメモリリーダーてな感じの数珠つなぎでようやく選択肢にこのドライブ(64GBSD)が出てきました。

でも、少し危険です・・・この状態だと充電できない!

これ途中で切れたらどうなるんですかね?恐ろしくて考えたくありません。。。
(切れてしまったようです 汗 いまUSBをそっと抜いて充電中・・・)

 

マイクロソフトって・・・

声を大にしていいたいのですけど

メディアクリエイションツールのUSBの空き容量を作業領域として使えない。

これクソ仕様です。容量の少ないWinタブレットを試乗にこれだけ放出しておいてこれですか?ていいたいです!

外部ドライブを接続できてそこを作業領域にできるって胸を張るかもしれませんが、
多くのタブレットはUSBが充電と兼用なんですよ。。。
一部なら仕方ないですけど、ほとんどそうなんですけど。。。

マイクロソフトはちゃんとテストとかモニターとかやったのかな?
こういうことはゴロゴロありますけどね・・・。

BONZの永久保証は最強すぎて不安になった

知る人ぞ知るBONZです。
アマゾンや楽天、ヤフーショッピングに出品しているショップです。
主にメモリを扱っているようです。
少し前は最安だったのですが、今はそうでもなくなっています。
でも、買うのはおすすめです。というのも永久保証がついているのです。

BONZは永久保証

もちろん折ったり、水濡れしたり、っていうのは保証されません。

BONZのメモリを買うとこんな保証書がはいっています。

ハンコまで印刷だし、ここに書いてあるような

  • 購入証明書
  • 納品書
  • 製品シール

ってなくって、配送は簡易なものでこの保証書が入っているだけなのです。
で、チョー不安になりますけど、結果から言いまして、まったく問題はありませんでした。
永久保証はちゃんと効きます。

私の場合・・・2年で故障

私の場合はラズパイ(Raspberry pi2)での使用でしたので、いつか壊れるだろうと思っていました。2年だと意外と持ったな、というイメージです。

保証規定の「正常な状態で使用中」がどんな状態を示すのか具体的に書いていないのでわかりません。物理的なダメージはもちろんダメでしょう。それは分かるんです。

ところが、SDカードの素子って、壊そうと思えば壊せます。強引に何度も書き換えを行うと壊れてしまいます。
わざと壊したわけではないとは言え、ラズパイ(Raspberry pi2)での使用は「正常な状態で使用中」なのでしょうか・・・?

とりあえず聞いてみた

悩んでいても仕方ないので、ヤフーショッピング(私はここで買った)の問い合わせからメールを送ってみました。

使用中に突然読み書きができなくなって、認識もしなくなってしまいました。
保障が効くかどうか教えてください。

とまあ、こんな感じです。
そうしたら

代替品を送りましたので、返信用封筒にてお手持ちのメモリをご返送ください。

てな感じでした。結局保証規定も何も関係ない感じでした・・・。良いのかな??

暫く待つとトランセンドの代替品が届きました。前回はノーブランドでしたのでなにげにグレードアップしました。

BONZはオススメ

というわけでBONZ自体のことが少し心配になる結果でしたが、
購入側としてはとてもおすすめできると思いました。

とは言えこれで経営が傾かれても困りますので、もうすこし規定を厳しくしても良いのかな、と邪推なことを思ったりしました。

USBメモリのマウントでトラブル[raspberry pi]

ファイルの保存場所としては、
システムのmicroSDの中じゃなくて、USBメモリにした方がいいんじゃないかと思いたち、テストを始めたのですが、いまいちうまく行っていません。

?書き込み権限がない!

差し込むと自動マウントされるのはいいのですが、
何かファイルを書き込もうとすると

「許可がありません」

と怒られてしまいます。sudoすればいけますが、何かと不便です。
一般ユーザーのcronで何かやろうとしてもすべて蹴られるってことですしね。
権限を緩めれば?とマウントポイントの /media/usb0 フォルダをchmodで変更しようとしても何も変化がないのです。

vfatでの方法は見つけた

usbの自動マウントはusbmountという機能で行われています。
設定ファイルは /etc/usbmount/usbmount.conf です。

これの FILESYSTEMS と FS_MOUNTOPTIONS です。

FILESYSTEMSは

FILESYSTEMS="ntfs vfat ext2 ext3 ext4 hfsplus"

としました。ntfs以外はデフォルトです。

FS_MOUNTOPTIONSはこのように変更します。

#FS_MOUNTOPTIONS="-fstype=ntfs,uid=pi,gid=pi,iocharset=utf8,codepage=932"
↓
FS_MOUNTOPTIONS="-fstype=vfat,iocharset=utf8,codepage=932,uid=500,gid=500,dmask=000,fmask=011"

変更しました、というか、これ以外はまったくうまく行きませんでした。

ntfs ext4 はまったくうまくマウントできない!

この-fstypeをntfsにしてみます。

$ lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sdb           8:16   1  1.9G  0 disk
mqsdb1        8:17   1  1.9G  0 part /media/usb1

マウントされたっぽいですが、

$ cd /media/usb1
-bash: cd: /media/usb1: 通信端点が接続されていません

なぬ?
何回やっても同じ結果で、アクセスできません。試しにFATに戻してみるとあっさりつながるのでNTFSがなにかおかしいようです。

次にext4でやってみます。

$ touch test
touch: `test' に touch できません: 許可がありません

見覚えのあるやつです。

試しに

FS_MOUNTOPTIONS="-fstype=ext4,iocharset=utf8,codepage=932,uid=500,gid=500,dmask=000,fmask=011"

とすると、自動認識もされなくなってしまいました。
まだ、

FS_MOUNTOPTIONS="-fstype=vfat,iocharset=utf8,codepage=932,uid=500,gid=500,dmask=000,fmask=011"

のほうがマウントされるだけマシです。

どうしてこうなるのかまったくわかりません・・・。

extundeleteでファイル復旧にチャレンジ![raspberry Pi]

それほど重要なファイルというわけではないのですが、
はずみでrmして、うっかりファイルを消してしまいました。
たまにやってしまいますね 汗
こういうときのためにrmは使わないで、
要らないファイルはどこかにmvしておく形式にしたほうが良い、とは思っているものの
またやってしまいました。

そこで、試しに復旧方法を調べてみると、なかなか良さそうなものがありました。

extundeleteで簡単復旧?!

extundeleteというので簡単に復旧できるそうです。
てなわけで、実行してみたいわけですが、コンパイルしないといけません。
本当は復旧したいディスクはリードオンリーにして使わないことが鉄則ですが、
起動ドライブであるためそうは行かず、
それでも一応USBメモリをさして、そこでコンパイルすることにしました。

 

> wget https://sourceforge.net/projects/extundelete/files/extundelete/0.2.4/extundelete-0.2.4.tar.bz2/download
> tar -zxvf extundelete-0.2.4.tar.bz2
> cd extundelete-0.2.4
> sudo ./configure
Configuring extundelete 0.2.4
configure: error: Can't find ext2fs library

ext2fsがないのでインストールします。
(実際はこういうことを復旧したいドライブでやるのはNGです)

$ sudo apt-get install ext2fs-dev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
Note, selecting 'e2fslibs-dev' instead of 'ext2fs-dev'
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  dc libasn1-8-heimdal libgssapi3-heimdal libhcrypto4-heimdal libheimbase1-heimdal
  libheimntlm0-heimdal libhx509-5-heimdal libkrb5-26-heimdal libroken18-heimdal libwind0-heimdal
  libxfce4ui-1-0 xfce-keyboard-shortcuts
これを削除するには 'apt-get autoremove' を利用してください。
以下の追加パッケージがインストールされます:
  comerr-dev e2fslibs e2fsprogs libcomerr2
提案パッケージ:
  doc-base gpart e2fsck-static
以下のパッケージが新たにインストールされます:
  comerr-dev e2fslibs-dev
以下のパッケージはアップグレードされます:
  e2fslibs e2fsprogs libcomerr2
アップグレード: 3 個、新規インストール: 2 個、削除: 0 個、保留: 282 個。
1,190 kB のアーカイブを取得する必要があります。
この操作後に追加で 798 kB のディスク容量が消費されます。
続行しますか? [Y/n] y
取得:1 http://mirrordirector.raspbian.org/raspbian/ jessie/main e2fslibs armhf 1.42.12-2 [173 kB]
取得:2 http://mirrordirector.raspbian.org/raspbian/ jessie/main e2fsprogs armhf 1.42.12-2 [728 kB]
取得:3 http://mirrordirector.raspbian.org/raspbian/ jessie/main libcomerr2 armhf 1.42.12-2 [59.7 kB]
取得:4 http://mirrordirector.raspbian.org/raspbian/ jessie/main comerr-dev armhf 2.1-1.42.12-2 [37.6 kB]
取得:5 http://mirrordirector.raspbian.org/raspbian/ jessie/main e2fslibs-dev armhf 1.42.12-2 [192 kB]
1,190 kB を 2秒 で取得しました (435 kB/s)
(データベースを読み込んでいます ... 現在 125349 個のファイルとディレクトリがインストールされています。)
.../e2fslibs_1.42.12-2_armhf.deb を展開する準備をしています ...
e2fslibs:armhf (1.42.12-2) で (1.42.12-1.1 に) 上書き展開しています ...
e2fslibs:armhf (1.42.12-2) を設定しています ...
libc-bin (2.19-18+deb8u4) のトリガを処理しています ...
(データベースを読み込んでいます ... 現在 125349 個のファイルとディレクトリがインストールされています。)
.../e2fsprogs_1.42.12-2_armhf.deb を展開する準備をしています ...
e2fsprogs (1.42.12-2) で (1.42.12-1.1 に) 上書き展開しています ...
man-db (2.7.0.2-5) のトリガを処理しています ...
e2fsprogs (1.42.12-2) を設定しています ...
(データベースを読み込んでいます ... 現在 125349 個のファイルとディレクトリがインストールされています。)
.../libcomerr2_1.42.12-2_armhf.deb を展開する準備をしています ...
libcomerr2:armhf (1.42.12-2) で (1.42.12-1.1 に) 上書き展開しています ...
libcomerr2:armhf (1.42.12-2) を設定しています ...
libc-bin (2.19-18+deb8u4) のトリガを処理しています ...
以前に未選択のパッケージ comerr-dev を選択しています。
(データベースを読み込んでいます ... 現在 125349 個のファイルとディレクトリがインストールされています。)
.../comerr-dev_2.1-1.42.12-2_armhf.deb を展開する準備をしています ...
comerr-dev (2.1-1.42.12-2) を展開しています...
以前に未選択のパッケージ e2fslibs-dev を選択しています。
.../e2fslibs-dev_1.42.12-2_armhf.deb を展開する準備をしています ...
e2fslibs-dev (1.42.12-2) を展開しています...
man-db (2.7.0.2-5) のトリガを処理しています ...
install-info (5.2.0.dfsg.1-6) のトリガを処理しています ...
comerr-dev (2.1-1.42.12-2) を設定しています ...
e2fslibs-dev (1.42.12-2) を設定しています ...

リベンジ!
prefixでUSBドライブの中を指定しています。

$ sudo ./configure -prefix=/media/usb0/src/extundelete-0.2.4/src
Configuring extundelete 0.2.4
Writing generated files to disk

成功した・・・?!

$ sudo make
make -s all-recursive
Making all in src
extundelete.cc: In function ‘ext2_ino_t find_inode(ext2_filsys, ext2_filsys, ext2_inode*, std::string, int)’:
extundelete.cc:1272:29: warning: narrowing conversion of ‘search_flags’ from ‘int’ to ‘ext2_ino_t {aka unsigned int}’ inside { } [-Wnarrowing]
    buf, match_name2, priv, 0};
                             ^

成功したのでしょうか・・・?

$ sudo make install
Making install in src
  /usr/bin/install -c extundelete '/media/usb0/src/extundelete-0.2.4/src/bin'

指示の通り /media/usb0/src/extundelete-0.2.4/src/bin にちゃんとバイナリができてました。
なんとか成功したっぽいです。

2:30頃のエポック時間です。

$ date -d "14:30" +%s
1501997400

指定して実行してみました。

$ ./extundelete --after 1501997400 --restore-all /dev/root
Only show and process deleted entries if they are deleted on or after 1501997400 and before 2147483647.
./extundelete: No such file or directory  /dev/root
./extundelete: No such file or directory when trying to open filesystem /dev/root

ところが「/dev/rootなんかないよ」と言われてしまいます。
どうやら起動しているシステムドライブは対象にできないようです・・・?sudoしてみても同じでした。

試しに接続してるUSBドライブでやってみます。

$ sudo ./extundelete /dev/sda1 --restore-all
./extundelete: Bad magic number in super-block when trying to open filesystem /dev/sda1

FATではだめってことです・・・。

仕方ないので、一度rpi-cloneでクローンドライブを作って、そのドライブに対して実行してみます。

$ sudo ./extundelete --after 1500000400 --restore-all /dev/sdb2
Only show and process deleted entries if they are deleted on or after 1500000400 and before 2147483647.
NOTICE: Extended attributes are not restored.
WARNING: EXT3_FEATURE_INCOMPAT_RECOVER is set.
The partition should be unmounted to undelete any files without further data loss.
If the partition is not currently mounted, this message indicates
it was improperly unmounted, and you should run fsck before continuing.
If you decide to continue, extundelete may overwrite some of the deleted
files and make recovering those files impossible.  You should unmount the
file system and check it with fsck before using extundelete.
Would you like to continue? (y/n)
y
Loading filesystem metadata ... 476 groups loaded.
Loading journal descriptors ... 32574 descriptors loaded.
Searching for recoverable inodes in directory / ...
4 recoverable inodes found.
Looking through the directory structure for deleted files ...
4 recoverable inodes still lost.
Unable to restore inode 3612833 (file.3612833): No undeleted copies found in the journal.
Unable to restore inode 3620865 (file.3620865): No undeleted copies found in the journal.
Unable to restore inode 3620897 (file.3620897): No undeleted copies found in the journal.
Unable to restore inode 3620898 (file.3620898): No undeleted copies found in the journal.

 

実行したドライブにRECOVERED_FILESというフォルダが作られます。
で、その中にファイルが吐き出されるはずなのですが・・・。
残念なことに、復活ならずででした。フォルダは空っぽ・・・。

extundelete というコマンドの有効性については気になりますので、もう一度検証はしたいと思います。