cron で回している rsync が 0 以外の終了コードを返してきたとき、その番号が何を意味するのかを調べるためのリファレンスです。まず一覧を載せて、そのあとで実際によく遭遇するコードの読み方とスクリプトでの扱い方を説明します。
終了コードは直後に echo $? で確認できます。
$ rsync -a /path/to/src/ /path/to/dst/ $ echo $? 0
終了コード一覧(rsync 3.4.4 の man ページより)
| コード | 意味(man の記述) | ざっくり言うと |
|---|---|---|
| 0 | Success | 成功 |
| 1 | Syntax or usage error | オプションの書き間違い |
| 2 | Protocol incompatibility | 両端の rsync が噛み合わない |
| 3 | Errors selecting input/output files, dirs | 入出力のファイル・ディレクトリを開けない |
| 4 | Requested action not supported | 相手側がその機能に未対応(32/64bit 差や古い rsync など) |
| 5 | Error starting client-server protocol | クライアント・サーバ間の開始に失敗 |
| 6 | Daemon unable to append to log-file | デーモンがログに書けない |
| 10 | Error in socket I/O | ソケット入出力エラー(接続断など) |
| 11 | Error in file I/O | ファイル入出力エラー(ディスクフルなど) |
| 12 | Error in rsync protocol data stream | プロトコルストリームのエラー |
| 13 | Errors with program diagnostics | 診断出力まわりのエラー |
| 14 | Error in IPC code | プロセス間通信のエラー |
| 20 | Received SIGUSR1 or SIGINT | シグナルで中断された(Ctrl+C など) |
| 21 | Some error returned by waitpid() | 子プロセスの待ち合わせでエラー |
| 22 | Error allocating core memory buffers | メモリ確保に失敗 |
| 23 | Partial transfer due to error | エラーで一部だけ転送された |
| 24 | Partial transfer due to vanished source files | 転送中にソースのファイルが消えた |
| 25 | The –max-delete limit stopped deletions | –max-delete の上限で削除が止まった |
| 30 | Timeout in data send/receive | データ送受信のタイムアウト(–timeout) |
| 35 | Timeout waiting for daemon connection | デーモン接続待ちのタイムアウト(–contimeout) |
このほか、リモート転送で ssh 自体が失敗すると、rsync は「unexplained error (code 255)」として ssh の終了コード 255 をそのまま返します。255 が出たら rsync ではなく ssh 接続(ホスト名、鍵、ポート)を疑ってください。
いちばんよく見る 23 と 24 の違い
実運用で目にする終了コードの大半は 23 か 24 です。どちらも「一部のファイルが転送できなかった」ですが、原因がはっきり区別されています。
24 は「転送中にソースのファイルが消えた」専用のコードです。一時ファイルやキャッシュを含むディレクトリを、システムを動かしたまま同期すればごく普通に出ます。詳しい原因と対処は rsync の「file has vanished」警告(code 24)の意味と対処 にまとめています。
23 は「消えた以外の何らかのエラーで転送しきれなかった」です。stderr に出ている個別のエラーメッセージ(rsync error: の前の行)を見て原因を特定します。よくあるのは次のパターンです。
Permission denied: 読み取り権限がない(root 以外で他ユーザーのファイルを含むディレクトリを同期した、など)No space left on device: 転送先のディスクフルcannot convert filename:--iconv使用時にファイル名の文字コード変換に失敗
最後の変換失敗は手元(rsync 3.4.4)で再現するとこうなります。
$ rsync -a --iconv=utf-8,ascii src/ dst/ [Receiver] cannot convert filename: 日本語ファイル.txt (Illegal byte sequence) rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1356) [sender=3.4.4] $ echo $? 23
ファイル名の文字コードがらみの対処は rsync でファイル名が文字化けするときの対処 を参照してください。
スクリプトで特定のコードだけ許容する
バックアップスクリプトでは「24 は正常扱いにしたいが、23 などの本当のエラーは検知したい」という要件が定番です。素直に書くとこうなります。
#!/bin/sh
rsync -a /path/to/src/ /path/to/dst/
rc=$?
case "$rc" in
0|24) exit 0 ;; # 成功、または転送中にファイルが消えただけ
*) exit "$rc" ;;
esac
set -e を使っているスクリプトでは、rsync が 0 以外を返した瞬間にスクリプトごと落ちてしまうので、いったん || で受け止めます。
#!/bin/bash
set -e
rc=0
rsync -a /path/to/src/ /path/to/dst/ || rc=$?
if [ "$rc" -ne 0 ] && [ "$rc" -ne 24 ]; then
exit "$rc"
fi
メッセージ出力ごと抑えたい(cron のエラーメールを止めたい)場合は、rsync ソース同梱の公式ラッパー support/rsync-no-vanished が使えます。詳しくは rsync の「file has vanished」警告(code 24)の意味と対処 で説明しています。
おまけ:パイプ越しの終了コードに注意
rsync の出力を tee などにパイプすると、$? はパイプの最後のコマンドの終了コードになってしまい、rsync の失敗を見逃します。bash なら PIPESTATUS を使うか、set -o pipefail を付けてください。
rsync -a src/ dst/ | tee rsync.log
rc=${PIPESTATUS[0]} # tee ではなく rsync の終了コード
さいごに
終了コードの意味は man rsync の EXIT VALUES 節が一次情報です(この記事の一覧は rsync 3.4.4 のものです)。0 と 24 だけを成功扱いにして、23 やそれ以外はメッセージを見て個別に対処する、というのが運用の基本形になります。
あわせて読みたい: