Linux 環境での Raspberry Pi 向け OS 書き込みTips

このエントリは Raspberry Pi Advent Calendar 2015 の12月08日分です.
昨日は @2box2boさんの RaspberryPiと公式タッチディスプレイでマインクラフトするお話 | 流連荒亡 でした.公式ディスプレイ欲しいです…….

最近 Raspberry Pi はサブPC 的に使っててネタがない(普通に Linux Desktop なので……)ので紙製ケースの紹介でもしようかと思っていたのですが,Raspberry Pi に OS を書き込むのによく使う dd 関連のネタが少し溜まっているので今回はこれを紹介しようと思います.(NOOBS だとほぼ関係なくコピーするだけでいいんですが……)
Rasbina jessie / Debian stretch で検証していますが,Linux なら導入手順以外同じだと思います.Mac OS X / UNIX 系の OS でも使えると思います.

– 紙ケースの一例 –

dd(dataset definition) は GNU Coreutils の中に入っているのでほとんどの GNU/Linux だと標準で導入されていると思います.とても便利だけど使い方を誤るとシステムやデータをいとも簡単に壊してしまえます.注意して実行しましょう.

進捗状況確認

dd で sd 書き込み中にどのくらい進んだのだろうと確認したくなることがあります.

kill -SIGUSR1

dd のプロセスに対して SIGUSR1 シグナルを投げると進捗が確認できます.

dd のプロセス番号を確認

$ ps -ef|grep dd
   :
root      9273 32218  0 17:57 pts/1    00:00:00 sudo dd of=/dev/sdz bs=4M
root      9276  9273  9 17:57 pts/1    00:00:00 dd of=/dev/sdz bs=4M

9276 なので以下のように

$ sudo kill -USR1 9276

で,こんな感じに表示されます.

0+243258 レコード入力
0+243258 レコード出力
1224679424 バイト (1.2 GB) コピーされました、 17.2794 秒、 70.9 MB/秒
0+302681 レコード入力
0+302681 レコード出力
1532985344 バイト (1.5 GB) コピーされました、 20.8063 秒、 73.7 MB/秒

なのでこんなとか

$ sudo pkill -SIGUSR1 ^dd

こんな感じで叩くと良い感じだと思います.

% watch -n30 'sudo pkill -SIGUSR1 ^dd`

pv(Pipe Viewer)

pv(Pipe Viewer) というパイプの状況を確認できるプログラムがあります.dd の間にこれを挟んで進捗状況を確認できます.

導入

$ apt install pv

利用例

% zcat 2015-11-21-raspbian-jessie.zip | pv | sudo dd of=/dev/sdz bs=4M
5.81GB 0:06:12 [15.2MB/s] [                           <=>                      ]

-N で 名前の,-c でクラスタオプションになります.これを活用すると複数のパイプの監視もできます.

$ zcat ./2015-11-21-raspbian-jessie.zip | pv -cN zcat | xz | pv -cN xz | dd of=./2015-11-21-raspbian-jessie.xz
     zcat: 8.41MB 0:00:05 [1.09MB/s] [   <=>                                   ]
       xz: 3.96MB 0:00:05 [1.06MB/s] [   <=>                                   ]

GNU ddrescue / ddrescue

dd じゃないけど dd の代わりに GNU ddrescue を利用するとプログレスが表示されます.

$ sudo apt install gddrescue
$ sudo ddrescue /dev/zero /dev/null --force
GNU ddrescue 1.19
Press Ctrl-C to interrupt
rescued:     2969 MB,  errsize:       0 B,  current rate:     354 MB/s
   ipos:     2969 MB,   errors:       0,    average rate:     742 MB/s
   opos:     2969 MB, run time:       4 s,  successful read:       0 s ago
Copying non-tried blocks... Pass 1 (forwards)

でも標準有力入力を受け付けないようです.

$ zcat ./2015-11-21-raspbian-jessie.zip | sudo ddrescue - /dev/sdz --force
ddrescue: Can't open input file: No such file or directory

類似の ddrescue だと標準入力もOKなようです.こちらの場合のコマンド名は dd_rescue です.

$ sudo apt install ddrescue
$ zcat ./2015-11-21-raspbian-jessie.zip | sudo dd_rescue - /dev/sdz
dd_rescue: (warning): input  file is not seekable!
dd_rescue: (warning): Illegal seek
dd_rescue: (warning): Don't use sparse writes for non-seekable output
dd_rescue: (info): ipos:     91136.0k, opos:     91136.0k, xferd:     91136.0k
                   errs:      0, errxfer:         0.0k, succxfer:     91136.0k
             +curr.rate:   144981kB/s, avg.rate:   144776kB/s, avg.load: 38.4%

ddすると重い/固まる

環境によって dd 実行中にとても重くなってマウスカーソルさえカクカク動くようになり並行して別の作業ができないようにます.

ionice

ionice を使って dd の優先度を下げることができます.

% zcat ./2015-11-21-raspbian-jessie.zip | sudo ionice -c2 -n7 dd of=/dev/sdz

pv -L

pv コマンドの -L オプションでパイプの帯域制限ができます.

   -L RATE, --rate-limit RATE
          Limit the transfer to a maximum of RATE bytes per second.  A suffix of "k", "m", "g",  or  "t"  can  be
          added to denote kilobytes (*1024), megabytes, and so on.
% zcat cros.img.gz | pv -L 8192k | sudo dd of=/dev/sdz

cgroup

リソース管理の cgroups で書き込み帯域制限をしてみます.以下は dd というグループを作成し,自分のシェルをそこに登録.SD Card のデバイスを書き込み制限 1k で設定し,dd で動作確認をしました.想定通り 1kB/s しか出なかったようです.

$ sudo mkdir /sys/fs/cgroup/blkio/dd
$ echo $$ | sudo tee -a /sys/fs/cgroup/blkio/dd/tasks 
26041
$ ls -l /dev/sdz
brw-rw---- 1 root disk 179, 0 12月  6 18:42 /dev/sdz
$ echo "179:0 1024" | sudo tee -a /sys/fs/cgroup/blkio/dd/blkio.throttle.write_bps_device 
179:0 1024
$ sudo dd if=/dev/zero of=/dev/sdz bs=4k count=10
10+0 レコード入力
10+0 レコード出力
40960 バイト (41 kB) コピーされました、 40.0136 秒、 1.0 kB/秒

書き込み速度が遅い

ブロックサイズ変更

dd コマンドはブロックサイズが 512バイトと小さいです.このサイズを変更することで1度に処理する容量が多くなり速度が改善されます.このサイズは bs オプションで設定できます.規定値と同じ 512バイトの場合は, bs=512.1MB の場合は bs=1M というようにして容量の単位(Yまで!)も指定できます.最近の私は 4~16M を指定しています.

$ zcat 2015-11-21-raspbian-jessie.zip | sudo dd of=/dev/sdz bs=4M

GNU ddrescue

GNU ddrescue は効率のいい処理を自動的に行うそうです.効率の良いブロックサイズを探すよりこれを導入したほうが早いかもしれません.

パーティション情報の削除

OS イメージをこれまで使っていた SD に上書きすると古いデータが残ってしまうことがあります.パーティション情報を削除してから書き込むと綺麗に行くようです.

Windows/Mac OS X の場合は SD Assosietion がフォーマッタを提供しているのでこれを利用すると良いと思います.

dd

dd コマンドでパーティション情報が入っているであろう先頭部分を消します.以下の例では 1M を 1回なので先頭の 1M が 0 で埋められます.2行目の hdparm はおまじないで kernel に書き換わったよと教えてあげています.最近は即時反映されるような感じですが,以前はこれを叩かないとうまく反映されないことが多かったです.(いちいち抜き差ししてみたり)

$ sudo dd if=/dev/zero of=/dev/sdz bs=1M count=1
$ sudo hdparm -z /dev/sdz

以下のように count を指定しない場合は全領域書き込みます.時間はかかるけど確実?

$ sudo dd of=/dev/zero of=/dev/sdz bs=10M

全領域書き込む場合は shred -z /dev/sdz でも良いですね.

wipefs

wipefs はパーティション情報の wipe をしてくれるツールです.一瞬で動作するし便利です.
util-linux パッケージ内の wipefs です.

デバイスだけ指定して実行すると現在のパーティションの状況が確認できます.-a オプションでパーティション情報が削除されます.便利.

$ sudo wipefs /dev/sdz
offset               type
----------------------------------------------------------------
0x1fe                dos   [partition table]

$ sudo wipefs -a /dev/sdz
/dev/sdz: 2 bytes were erased at offset 0x000001fe (dos): 55 aa
/dev/sdz: calling ioctl to re-read partition table: 成功です
$ sudo wipefs /dev/sdz

mount中のファイルシステムに書き込もうとすると終了するscript

dd は便利ですが,書き込み先を間違えるとシステムやデータを破壊してしまいます.私もつい一昨日やってしまいましたorz
#何故か /dev/mmcblk0 が /dev/sda へのシンボリックリンクとなっていた.
600GB の 先頭 1.5GB だからデータはほとんど救出できるだろうと思ったのですが,LUKS で暗号化していたのでメタデータが破壊され復旧は無理そうです.幸いデイリーバックアップがあるのでそちらから復旧中です.
(復旧中なのにどうやって書いているかというと Raspberry Pi 2 B にキーボードマウスモニタ取り付けて ReText で書いています.Web は midori でも重いので ssh -CY してファイルサーバのブラウザを使っています.使い慣れないキーボードが不便です><)

こういう悲しいことが起こらないようにできないものかと mount 中のデバイスに書き込もうとすると失敗させることができればいいのでは?と思ったのですがそういったオプションなどが見当たりませんでした.
それっぽいscript を書いてみました.

利用方法は,/usr/local/bin/dd としてこのスクリプトを用意して実行権をつけておいて通常の dd コマンドのように使うだけです.

$ wget -O - https://gist.githubusercontent.com/matoken/e051cefb78594520038d/raw/9ac20f31c590a043f1774f82068a99846ab7c4bb/dd.sh | sudo tee /usr/local/bin/dd
$ sudo chmod +x /usr/local/bin/dd
$ which dd
/usr/local/bin/dd
$ sudo which dd
/usr/local/bin/dd

マウント状態で書き込もうとすると失敗する.

$ sudo dd if=/dev/zero of=/dev/sdz
/dev/sdz seems to specify the file system in the mount.
Force Quit.

アンマウントして再実行すると dd が開始される.

$ sudo umount /dev/sdz1 
$ sudo dd if=/dev/zero of=/dev/sdz1

あまりテスト出来ていないので何かあったら教えてもらえると助かります.

おわり

ということで Raspberry Pi や kobo の SD Card に何度も書き込んだ時の Tips まとめみたいなものでした.ここ間違ってるよとかもっといい方法あるよとかおしえてもらえると助かります.(特に誤って書き込まないようにする方法)

あひる焼きfortune

この記事は あひる焼き Advent Calendar 2015 – Adventar の12月05日分の記事です.

みんなでまったり #あひる焼き すればええんじゃないかなと思います。

ということで最近焼いたあひるの話を.

発端

fortune というフォーチュンクッキーのような格言をランダムに表示するプログラムがあります.様々な辞書データが存在していて自作も出来ます.

pi@raspberrypi ~ $ sudo apt install fortunes            # fortuneの導入
pi@raspberrypi ~ $ fortune                              # fortuneの実行
Some of us are becoming the men we wanted to marry.
                -- Gloria Steinem
pi@raspberrypi /tmp $ cat <<__EOF__> data               # fortuneのデータ作成
テスト
%
1行目
2行目
%
__EOF__
pi@raspberrypi /tmp $ strfile data                      # データ変換
"data.dat" created
There were 2 strings
Longest string: 16 bytes
Shortest string: 10 bytes
pi@raspberrypi /tmp $ ls data*
data  data.dat
pi@raspberrypi /tmp $ fortune data                      # 自作データを利用
1行目
2行目
pi@raspberrypi /tmp $ fortune data
テスト

その辞書データに @ahiru3netさんのあひる焼きに対するmentionを使うと楽しいかもしれないと思いました.でもデータを集めるのが面倒だなとつぶやいたところ @shimadahさんにGitHub を教えてもらいました.

それを元にコネコネして……うまくいかないところに@ahiru3netさんの助言.

焼けた

やってることはahiru_yakunaプラグインのmentionのデータをもらってきて乱暴にfortuneで利用できる形式に変換して~/.zshrc に登録してログイン時に台詞を出すようにしています.

mkdir ~/.fortune;wget -O - https://github.com/Na0ki/ahiru_yakuna/raw/master/config.yml|grep ^\-\ \" | sed 's/^-\ \"//'| sed 's/"$/\n%/' | sed 's/\\n/\n/g' > ~/.fortune/ahiruyaki && strfile ~/.fortune/ahiruyaki ~/.fortune/ahiruyaki.dat && echo fortune ~/.fortune/ahiruyaki >> ~/.zshrc

これでログインのたびに以下のようにメッセージが表示されるようになりました :)

焼いちゃうのか?!本当に焼いちゃうのか?!
pi@raspberrypi ~ $

もっと焼く

でもメッセージだけだとちょっとさみしいです.
そこで cowsay を使ってみます.cowsay はアスキーアートで書かれた牛などのキャラクタに指定した台詞を喋らせることの出来るプログラムです.都合のいいことに選択できるキャラクタの中にあひるがいます.あひるに喋ってもらいましょう!

pi@raspberrypi ~ $ sudo apt install cowsay                  # cowsay 導入
pi@raspberrypi ~ $ cowsay hello cow                         # cowsay 実行
 ___________
< hello cow >
 -----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
pi@raspberrypi ~ $ cowsay -f duck hello duck                # あひるに喋らせる
 ____________
< hello duck >
 ------------
 \
  \
   \ >()_
      (__)__ _
pi@raspberrypi ~ $ cowsay -f duck あひる焼き                 # 日本語を喋らせる
 _______
< あひる焼き >
 -------
 \
  \
   \ >()_
      (__)__ _

日本語を喋らせると吹き出しがずれてしまいます.あひる焼きの台詞の殆どは日本語なのでこのままではまずいです.調べてみるとバグレポートされていました.

中国語?もやっぱりずれちゃうみたいです.
文字数と見た目のキャラクタの文字数のズレから起こっているようです.とりあえず日本語だけでも動くように出来ないかと euc-jp に変換して文字数を確認してといったダメな修正をしていたところGoogle+の以下の投稿のコメントで +Masakazu Takahashiさんがさくっとパッチを作ってくれました!

このパッチは報告しましたが,取り込まれてもstretch以降でしょう.ということでDebianだと以下のようにしてソースを入手してパッチを当てることが出来ます.

pi@raspberrypi ~/src $ sudo apt install libtext-charwidth-perl      # 必要なパッケージの導入
pi@raspberrypi ~/src $ apt-get source cowsay                        # cowsay の source 入手
pi@raspberrypi ~/src $ cd cowsay-3.03+dfsg1                         # ディレクトリ移動とパッチ適用
pi@raspberrypi ~/src/cowsay-3.03+dfsg1 $ wget -O - https://gist.githubusercontent.com/emasaka/639a9168c6a9ddba044f/raw/1a55ec58ded59b3181f1721dbbe814a38d5ea4cb/cowsay-mbswidth.patch | patch -i -
patching file cowsay
pi@raspberrypi ~/src/cowsay-3.03+dfsg1 $ ./cowsay -f duck あひる焼き
 ____________
< あひる焼き >
 ------------
 \
  \
   \ >()_
      (__)__ _

~/bin 辺りにコピーして使ったり,以下のような感じで既存のパッケージを置き換えてしまってもいいかもしれません.

pi@raspberrypi ~/src/cowsay-3.03+dfsg1 $ vi debian/control
- Depends: ${misc:Depends}, ${perl:Depends}
+ Depends: ${misc:Depends}, ${perl:Depends}, libtext-charwidth-perl
pi@raspberrypi ~/src/cowsay-3.03+dfsg1 $ dpkg-buildpackage -b
pi@raspberrypi ~/src/cowsay-3.03+dfsg1 $ sudo debi

さて,fortuneのことを忘れてしまいそうですが以下のようにしてあひる焼きfortuneの結果をあひるに喋らせます.

pi@raspberrypi ~ $ cowsay -f duck `fortune ~/.fortune/ahiruyaki`
 ______________
< ヒッヒッヒッ >
 --------------
 \
  \
   \ >()_
      (__)__ _

いい感じです :)

~/.profile 辺りに登録しちゃいましょう.aliasも設定してみます.

pi@raspberrypi ~ $ echo 'alias a="fortune ~/.fortune/ahiruyaki | cowsay -f duck"' >> ~/.profile 
pi@raspberrypi ~ $ echo a >> ~/.profile

これでlogin時や a と入力することで実行されます.

Last login: Fri Dec  4 23:32:05 2015 from 192.168.2.210
 ________________________________________________________________________________
/ あひる焼きというものには鮮度があります。焼けば焼くほどに、あひる焼きとは廃れて \
\ いくものなのです。                                                             /
 --------------------------------------------------------------------------------
 \
  \
   \ >()_
      (__)__ _
pi@raspberrypi ~ $ a
 ________________________
< バーニング通帳!!!! >
 ------------------------
 \
  \
   \ >()_
      (__)__ _

Xでも焼く

GUI の X 版のcowsayも存在します.こいつも試してみましょう.

pi@raspberrypi ~ $ sudo apt install xcowsay
pi@raspberrypi ~ $ xcowsay `fortune ~/.fortune/ahiruyaki`

https://www.flickr.com/photos/119142834@N05/23490968856/in/dateposted-public/

なかなか特徴的なcowが喋りました.せっかくなのであひるに喋らせましょう.吹き出しの向きと位置を変えてあひる画像を指定しています.

pi@raspberrypi ~ $ wget https://github.com/Na0ki/ahiru_yakuna/raw/master/ahiru240.jpg -O ~/.fortune/ahiru240.jpg
fortune ~/.fortune/ahiruyaki | xcowsay -l --bubble-at=0,-60 --image=$HOME/.fortune/ahiru240.jpg

https://www.flickr.com/photos/119142834@N05/23434841661/in/dateposted-public/

背景がちょっと邪魔なので透過処理をしてみます.

https://www.flickr.com/photos/119142834@N05/23149788589/in/dateposted-public/

いい感じです :)
例によってaliasにしておきます

pi@raspberrypi ~ $ echo alias xa='fortune ~/.fortune/ahiruyaki | xcowsay -l --bubble-at=0,-60 --image=$HOME/.fortune/ahiru240.png' >> ~/.profile

そんなこんなでみんなのおかげであひるがいい感じに焼けるようになりました.@shimadahさん, @ahiru3netさん, @emasakaさんありがとうございました!

#そうそう,以前はフレームバッファでもあひる焼きしてました.