汎用バックアップスクリプト tarbut

tar にはコマンドオプションが多い。しかもバックアップ対象も多いと、例えば:

tar -g /home/hoge/cache/test.snar --exclude-from=/home/hoge/settings/exclude.txt -C / -czf /home/hoge/backup/test_050817.tgz home/hoge/data home/hoge/www home/hoge/.* home/hoge/Maildir

というようなことになり、とてもいちいちタイプしてはいられない。また、こうしたコマンドをひとつひとつシェルスクリプトにするのも、あまり格好良くないし、バックアップしたアーカイブの管理も面倒だ。そこで、システム上の全てのユーザが共通して使えて、システマティックに管理ができるスクリプトを作成して使っている。それが tarbut (TAR BackUp Tool) だ。

tarbut の機能一覧

  1. 単純なコマンド
    例えばフルバックアップなら `tarbut <target_name> ' でOK。
  2. バックアップは「ターゲットリスト」で管理
    `sample' というターゲットを作るには、sample.lst というファイルを作成し、1 行にひとつずつパスを書いておく (パスはいくつでも列挙可能)。 `tarbut sample' とコマンドすれば、sample.lst に書いてある全てのパスが sample.tar にアーカイブされる。シェルスタイルのワイルドカードの使用も可能。
  3. 動作設定ファイルでカスタマイズ
    動作設定ファイル tarbut.conf で幾つかの変数をセットすることにより、圧縮方式 (gzip/bzip2/なし) などが簡単に切替可能。ターゲットリストを管理するディレクトリ、バックアップアーカイブを保存/管理するディレクトリなどもこのファイルで設定/変更する。設定ファイルはシステムデフォルト (/etc/tarbut.conf) の他に、各ユーザのホームディレクトリ (~/tarbut.conf) にも置けるので、ユーザ毎に設定が可能。
  4. インクリメンタルバックアップ機能
    インクリメンタル (増分) バックアップも `tarbut --level=0 <target_name>' という簡単なコマンドオプションで実行できる。 --level=0 がインクリメンタルの土台となるフルバックアップアーカイブの作成、 --level=1 とすればそこからの増分アーカイブが作成される。さらに (例えば翌日に) --level=1 を行えば、前回のレベル1 バックアップからの増分が、ファイル名に日付時刻を持ったファイルにアーカイブされる。
  5. 書庫の管理とステータスの表示機能
    バックアップアーカイブ保存ディレクトリの状態を確認 (--status <target_name> ) したり、インクリメンタルレベル1 アーカイブだけの削除、レベル 0/1 の両削除などの作業も単純なコマンドで一発。
  6. マルチボリュームに対応
    複数の連続したファイルに渡ってアーカイブを作る GNU tar の「マルチボリューム」動作に対応。設定ファイルで上限サイズを設定しておくだけで、あとはスクリプトが自動制御。

ダウンロード

TAR ボール
コンポーネント単体

更新履歴

動作環境

下記のシェル/ユーティリティが利用可能な UNIX 系システム

想定外事項

tarbut ユーザーズマニュアル

インストール

アーカイブをダウンロードし、適当な一時ディレクトリで解凍する:

user$ tar -xzpvf tarbut-1.x.x.tgz

以下のコンポーネントが解凍される:

tarbut/
   └ tarbut (スクリプト本体)
   └ tarbut.conf (動作設定ファイル)
   └ tarbut.d/
           └ sample.lst (ターゲットリスト記述例)
           └ sample.exc (リスト例`sample'用のバックアップ除外対象パターン定義)
           └ excludes   (全ターゲット共通の除外パターン定義)

スクリプト本体をパスの通ったディレクトリに置く。例えば:

root# cp tarbut /usr/local/bin
root# chmod 755 /usr/local/bin/tarbut

動作設定

動作の設定は tarbut.conf にある以下の変数で設定する。ディレクトリ名の最後のスラッシュは無用。ここで指定した各ディレクトリは自動的には作られないので、実行前に作成しておく必要がある。

tarbut.conf はシステムデフォルト設定 /etc/tarbut.conf と、ユーザ毎の設定 ~/tarbut.conf の 2 段構え。ユーザによる設定変数は、グローバルファイルの設定よりも優先される。このファイルはメインスクリプトからインクルードされるので、記述様式は通常の BASH スクリプト規則に従う。

グローバル /etc/tarbut.conf の例:

CONFDIR=/etc/tarbut.d
DESTDIR=/backup
CACHEDIR=/var/lib/tarbut
COMPRESS=none
OPT="--ignore-failed-read"
AUTOCLEAN_LEVEL1=0
MAX_DESTSIZE=716000
MULTI_COMP_THRESHOLD=90
MAX_VOL=9

ユーザの ~/tarbut.conf の例:

CONFDIR=~/tarbut.d
DESTDIR=~/archives
CACHEDIR=~/archives/cache
COMPRESS=gzip
OPT="--verbose"
AUTOCLEAN_LEVEL1=1
MULTI_COMP_THRESHOLD=50

OPT 変数には、以下の tar オプションは書く必要がない。スクリプト本体が適宜付加するので、書いてはならない

バックアップターゲットの設定

ターゲット.lst ファイル

tarbut に、アーカイブに納める対象ファイルやディレクトリを指示するファイル。 tarbut は、コマンド引数で渡された <TARGET> を名前に持つ <TARGET>.lst ファイルを CONFDIR 直下から探し、その内容をシェルを通じて tar に渡す。つまり、sample.lst という名前のファイルを作成することそれ自体が、`sample' という「ターゲット」を「定義」したことになる。リストファイルつまりターゲットはいくつでも作成できる。

sample.lst を見ていただければ分かるが、ターゲットリストファイルには、バックアップしたいファイルやディレクトリのパスを 1 行に 1 つずつの単位で書く。記述のコツに関しては、tar プログラムそのものに依存する部分なので、 tar におけるディレクトリの扱われ方 (-C オプションなど) について少しばかり理解しておく必要がある。さわりだけ述べれば、以下のようになる:

※ いや、「シェルスタイル」ではなく、実際、アーカイブ時においては、ワイルドカードは tar でなくシェルによって展開・解釈されているとしか思えない。`-C /PATH' とワイルドカードを使うと、バックスラッシュでエスケープしようがシェル展開を阻止する `set -f' を唱えようが、tar はワイルドカードを正常に解釈できず「`hoge/*' というファイルはない」と跳ねつけられて。かたや、/PATH へあらかじめ cd しておくとエラーは出ないのだ。tarbut 1.2.0 で、-C をやめて事前に cd する方式に改めた。

tarbut 独自の仕様:

除外パターンファイル

excludes ファイルと <TARGET>.exc ファイルは、アーカイブしない対象を定義するファイル。 excludes ファイルはそのユーザの全ターゲットに適用するデフォルトの除外パターン、 <TARGET>.exc はそのターゲットにのみ適用する除外パターンだ。 `sample' ターゲットを例にとると、sample.exc ファイルが存在すれば (中身が空でも) その内容が採用され、 sample.exc ファイルがなければ excludes の設定が採用される。両ファイルの「総和」ではない点に注意。この仕様によって、excludes に記述がある時でも、空の sample.exc ファイルを置いておけば、sample ターゲットではいかなる除外もさせないようにできる。

この機構は tar 自体の --exclude-from 機能を利用している。現在のところ GNU tar には下記のような仕様と注意事項 (GNU tar Reference Manual) がある。以下には tarbut 独自の仕様も補足として一部含めている。:

tarbut のコマンド

基本書式は、

tarbut [option] <TARGET>

<TARGET> はリストファイルから拡張子 .lst を除いた名称であり、どのオプションの時も必ず指定しなければならない (--help--list を除く)。オプションは、なし、または下記のいずれかひとつ。いずれも、<TARGET> で指定されたターゲットに属するオブジェクトだけを処理する。下表中の <EXT> はバックアップアーカイブの拡張子で、 tarbut.confCOMPRESS 設定によって変化する (tar, tgz, tar.bz2 のいずれか)。下記と同様の内容は tarbut --help または -h でも (英語だが) 見られる。

--level=0 インクリメンタルバックアップ動作を行う。このように右辺が 0 の場合は、インクリメンタルバックアップの土台となるフルバックアップを行う。取られたバックアップは <TARGET>_lev0.<EXT> という名称になる。その際、 CACHEDIRスナップショットファイル <TARGET>.snar が作成され、もし以前に作成された <TARGET>.snar が既に存在すれば、古いものは.back を付けて改名される。また、 tarbut.confAUTOCLEAN_LEVEL11 となっている場合は、既に存在する Level-1アーカイブ (下記) を、今回のアーカイブ処理が正常に完了したあと全て削除する。
--level=1 やはりインクリメンタルバックアップだが、前回のインクリメンタルバックアップ時に作成あるいは更新されたスナップショットファイルを参照して、前回からの増分をアーカイブし、同スナップショットファイルを更新する。少なくとも Level-0 アーカイブとスナップショットファイルが存在しなければ、動作を拒否する。Level-1 の結果にできるアーカイブは作成時のタイムスタンプを利用して <TARGET>_yymmddHHMM.<EXT> となる。
オプションなし 通常のバックアップを行う。存在するインクリメンタルバックアップやスナップショットファイルには一切タッチしない。定期外のフルバックアップを行う場合や、そもそも常にフルバックアップしか行わない人に適している。
--clean インクリメンタル Level-1 の一連のアーカイブ全てと、既に *.snar.back に改名されている不要になったスナップショットファイルを削除する。
--cleanall インクリメンタル Level-0, Level-1 の一連のアーカイブとスナップショットファイルを削除する。
--kill 上記に加え、インクリメンタルでない通常のアーカイブも削除する。
--status アーカイブの簡単な一貫性チェックを行い状態を表示する。フルバックアップの有無や、インクリメンタルバックアップのアーカイブがあるのにスナップショットファイルがなかったり、 Level-1 アーカイブ群のうち最も古いものより Level-0 アーカイブのほうが新しいといった異常が点検できる。
--list 有効なターゲットをリストアップする。

cron への登録

ユーザレベルのバックアップジョブの例

hoge というユーザは `sample' ターゲットのフルバックアップを 1 日おきに取りたいとしよう。実行時刻は朝 3:30 とする。

hoge$ crontab -e

とコマンドすると vi か何か (システムの設定に依存) が開き、ユーザ専用 crontab ファイルの編集状態になるので、下のように入力してから保存終了する:

30 3 */2 * * /usr/local/bin/tarbut sample

するとジョブは自動的に /var/spool/cron/hoge ファイルとして保存され、準備OKとなる。 cron デーモンは 1 分毎に /var/spool/cron/ の変更を監視しているので、 cron を再起動する必要はない。

システムレベルのバックアップジョブの例

ここでは、せっかくなので、インクリメンタルバックアップを取り入れた、少しだけ複雑なスケジュールを組むことにしよう。ポリシーは:

下記のようなスクリプト (仮に systemtarbut としよう) を作ってそのパーミションを root.root 700 にする。そして、例えば /etc/cron.misc/ など、既存の cron スケジュールで run-parts に網羅されていないディレクトリに置く。 /usr/bin/run-parts は、 RedHat 系で crontabs パッケージとともにインストールされるシェルスクリプトで、指定したディレクトリ内にあるクリプトファイル (ただしファイル名が `~' または `,' で終わるものを除く) を全て実行するというもの。

#!/bin/sh
if [ "$1" = "1" ]; then
  TARBUT="/usr/local/bin/tarbut --level=1"
else
  TARBUT="/usr/local/bin/tarbut --level=0"
fi
$TARBUT sample
$TARBUT some_else

root で実行するジョブとして登録するので /etc/crontab をエディタで開き、以下の記述を追加する:

05 4 * * 0   root /etc/cron.misc/systemtarbut   (日曜日の Level-0)
05 4 * * 1-6 root /etc/cron.misc/systemtarbut 1 (月~土曜日の Level-1)

上の /etc/crontab 編集時には、ファイル冒頭にある環境変数宣言も確認しておこう。もし `HOME=/' という記述があれば、ここで cron ジョブ化する tarbut 用の tarbut.conf は、ルートファイルシステム直下に置かなければならない。変数宣言の内容のほうを変えるのは、他のジョブに影響を及ぼす可能性があるのでやめたほうがいい。

以上で準備は完了。 cron は 1分毎に /etc/crontab の最終更新日時をチェックしているので、 cron を再起動する必要はない。 sample ターゲットを例にすれば、 $DESTDIR 及び $CACHEDIR には、日曜の朝には sample_lev0.tarsample.snar ができ、月曜には前日からの増分だけの sample_05200405.tar ができ、火曜には sample_05210405.tar が....という具合で、期間の終わりである土曜の朝には、

sample.snar
sample_lev0.tar
sample_05200405.tar  sample_05210405.tar  sample_05220405.tar
sample_05230405.tar  sample_05240405.tar  sample_05250405.tar

というワンセットのバックアップが揃うことになる。言うまでもないが、なるべく毎日、未明にできたアーカイブと更新されたスナップショットファイルを別の媒体にコピーすることをお勧めする。なお、 Level-1 アーカイブはコピーでなく「移動」でもいいが、 tarbut --status の際の一貫性チェックの関係で、 Level-0 アーカイブは、ハードディスクに余裕があれば $DESTDIR にも残しておきたい。スナップショットファイルは必ず残さないと意味がない。リストア方法は前ページでクドいほど説明した。

バックアップアーカイブの CD-RW/DVD-RW への書き出し

GNOMEデスクトップでの手動書き込み

Fedora Core 3 では、GNOME + Nautilus に CD/DVD ライターが統合されているので、「プログラムを指定して実行」窓かファイルブラウザのロケーションバーで、 burn:/// と入力するだけで、あとは直感的に書き込みができる。この CD/DVD ライティングアプリケーションは、リライタブルメディアであれば、まず全体を高速消去してから書き込みを行うようになっているようだ。

書き込みがうまくいかない時は以下の項目を検討してみる:

スクリプトの使用

上記の Nautilus GUI アプリケーションも、舞台裏を覗いてみれば実は mkisofscdrecord を使っている。だったらということで、 BASH スクリプトで書き込みルーティンを作ってみた。この write-cd スクリプトは、CD-RW を (必要であれば) 一旦消去してから、引数で指定したディレクトリにあるファイル/ディレクトリを RW に書き込む (パケットライトではない)。 -v オプションを指定しない限りは、エラー時以外は一切メッセージを出さないようにしたので、 cron に組み込むにも便利だろう。現状、筆者の環境には DVD-RW ドライブはないので、DVD の場合は cdrecordmkisofs に渡すオプション引数の部分を多少調整する必要があると思われる。

write-cd スクリプトはこちら

留意点がふたつ。 cdrecord は一部 root 権限がないと達成できないシステムコールを行うので、 write-cd スクリプトファイルは所有者もグループも root にして、 SetUID root (`chmod 4755') しておいたほうがいい(※)。また、同スクリプト冒頭の環境変数設定のうち、
DEV=/dev/hdc
という部分は、 Fedora Core 1/2 と 3 とでは指定方法が異なる。これは途中から cdrecord仕様が変わり SCSI エミュレーションが不要となったため。 1 や 2 では `1,0,0' などといったもの (`cdrecord -scanbus' でプローブできる) になるが、 Fedora Core 3 では通常のブロックデバイスを指定する。 WRITESPEED=4 も自分のマシンの備える CD-RW のスピードに合わせて適宜直していただきたい。使い方の概略は `write-cd -h' で見られる。

※ 最近のLinux環境ではスクリプトの SetUID root が効かないようになっている。write-cdスクリプトを呼ぶ小さなCラッパーをビルドしてそれを SetUID rootする必要がある。