[pSync って何?] [動作環境] [インストール [実行ファイルのインストール] [同期ディレクトリの設定] [インストールの確認]] [使い方] [エラーメッセージと終了コード] [変更履歴] [ライセンス] [その他] [技術資料 [通信プロトコル] [データフロー] [同期アルゴリズム [psync_new()] [psync_free()] [run()] [使用例]] [シリアライザ [WRITE()] [READ()]]]

pSync

pSync って何?

DropboxRaspberry Pi で動かないので、その代替えに作ったネットワーク双方向ファイル同期ツール。

特徴は以下の通り。

動作環境

pSync を動作させるには下記環境が必要。

インストール

同期元と相手の両方に 実行ファイルのインストール同期ディレクトリの設定 の作業が必要。

実行ファイルのインストール

下記で実行ファイルが ~/bin/ へインストールされる。

$ curl -O http://kobayasy.com/psync/psync-2.34.tar.gz
$ tar xzf psync-2.34.tar.gz
$ cd psync-2.34
$ ./configure --prefix=$HOME
$ make install

同期ディレクトリの設定

下記は ~/pSync/Private/~/pSync/Work/ を同期ディレクトリに設定して、それぞれに識別名 privatework を付ける設定例。

$ install -m700 -d ~/pSync/Private
$ install -m700 -d ~/pSync/Work
$ cat <<EOF > ~/.psync.conf
#ID     Directory
private pSync/Private
work    pSync/Work
EOF
$ chmod 600 ~/.psync.conf

インストールの確認

下記を実行。 下記は同期相手が guest@example.com の場合の例なので実際の相手に合わせて置き換える事。

$ psync --help
pSync 2.34 (protocol pSp1)

Usage: psync [--sync] [-v|-q] [USER@]HOST[#PORT]
       psync --put [-v|-q] [USER@]HOST[#PORT]
       psync --get [-v|-q] [USER@]HOST[#PORT]
       psync --help

USER@HOST#PORT
  HOST           hostname
  USER           username (default: current login user)
  PORT           SSH port (default: 23)

runmode
  -s, --sync     synchronous mode (default)
  -p, --put      oneway put mode
  -g, --get      oneway get mode

options
  -v, --verbose  verbose mode (default)
  -q, --quiet    quiet mode

subcommand
  --help         show this help

$ ssh guest@example.com psync --help
pSync 2.34 (protocol pSp1)
(中略)
$

使い方

下記を実行するだけ。 下記は同期相手が guest@example.com の場合の例なので実際の相手に合わせて置き換える事。 これで同期ディレクトリ内のファイルが同期相手と同期する。

$ psync guest@example.com
private
work
$ 

エラーメッセージと終了コード

Skip, not ready
識別名が示す同期ディレクトリが既に同期処理中である為、同期処理を飛ばした事を示す。 他ホストからのアクセスや cron による自動起動で、裏で pSync が動作しているのでその終了を待つ。 裏で動作している pSync は下記コマンドで確認できる。
$ ps ax | grep psync
裏で pSync が動作していないのにこのメッセージが出る場合は前回の同期処理が Ctrl-| 入力や kill -9 pid コマンドで強制終了された等の原因で、同期ディレクトリがロックされた状態のまま残ってしまっている可能性が考えられる。 その場合、下記コマンドで強制的にロックを解除する事が出来る。
$ rm -r 同期ディレクトリ/.psync/lock
0, No error
ファイル同期成功(エラーなし)。
1, Unknown
不明なエラー。
2, File type
同期ディレクトリ内に非対応な種類のファイルが存在している。 もしくはディレクトリでないファイルを同期ディレクトリに指定している事を示している。 pSync が対応しているのは 通常ファイル と ディレクトリ、シンボリックリンク のみなので、デバイスファイル等、その他の種類が含まれていないかを確認して、修正するか削除する。 下記コマンドでこのエラー原因のファイルを検出出来る。
$ find 同期ディレクトリ ! -type f ! -type d ! -type l
3, File permission
同期ディレクトリ自身かその中に、ユーザー権限で読み出し出来ないファイル か ユーザー権限でアクセスできないディレクトリ が存在する事を示している。 その場合,パーミッションを修正するか削除する。 下記コマンドでこのエラー原因のファイルを検出出来る。
$ find 同期ディレクトリ -type f ! -readable -o -type d ! ( -readable -writable -executable )
4, Make file
同期ディレクトリ内へのファイル生成に失敗した事を示している。 ディスク容量が足りなくなった場合もこのエラーになる。
5, Open file
同期ディレクトリ内のファイルオープンに失敗した事を示している。
6, Write file
同期ディレクトリ内へのファイル書き込に失敗した事を示している。 ディスク容量が足りなくなった場合もこのエラーになる。
7, Read file
同期ディレクトリ内のファイル読み出しに失敗した事を示している。
8, Link file
同期ディレクトリ内でのハードリンク生成に失敗した事を示している。 ディスク容量が足りなくなった場合もこのエラーになる。
9, Remove file
同期ディレクトリ内のファイル削除に失敗した事を示している。
10, Move file
同期ディレクトリ内でのファイル移動に失敗した事を示している。
11, Write file-stat
同期ディレクトリ内のファイルパーミッションか更新時刻情報の書き換えに失敗した事を示している。
12, Read file-stat
同期ディレクトリ内のファイルステータス読み出しに失敗した事を示している。
13, Upload file-stat
同期情報の(原因発生側から見て)アップロードに失敗した事を示す。 途中で同期先との接続が切れた場合、このエラーになる。
14, Download file-stat
同期情報の(原因発生側から見て)ダウンロードに失敗した事を示す。 途中で同期先との接続が切れた場合、このエラーになる。
15, Upload file
同期ファイルの(原因発生側から見て)アップロードに失敗した事を示す。 途中で同期先との接続が切れた場合、このエラーになる。
16, Download file
同期ファイルの(原因発生側から見て)ダウンロードに失敗した事を示す。 途中で同期先との接続が切れた場合、このエラーになる。
17, Make data-file
同期情報ファイル(同期ディレクトリ/.psync/last)の生成に失敗した事を示す。 ディスク容量が足りなくなった場合もこのエラーになる。
18, Open data-file
同期情報ファイル(同期ディレクトリ/.psync/last)の読み出しに失敗した事を示す。
19, Write data-file
同期情報ファイル(同期ディレクトリ/.psync/last)への書き込みに失敗した事を示す。 ディスク容量が足りなくなった場合もこのエラーになる。
20, Read data-file
同期情報ファイル(同期ディレクトリ/.psync/last)からの読み出しに失敗した事を示す。
21, Remove data-file
バックアップ保持ディレクトリ(同期ディレクトリ/.psync/ファイル同期日時)の削除に失敗した。
22, Memory
メモリ不足を示す。 他のプロセスを終了させて使えるメモリを増やせば解決するはず。
23, System
システム的な原因によるエラーを示す。
24, Interrupted
Ctrl-C 入力か kill pid コマンド、もしくは同期相手との接続切れによる中断を示す。
25, Protocol
同期相手との接続に失敗したかプロトコルが合わない。 引数の同期相手ホスト名とログイン名に間違いがないかを確認。 同期相手の pSync が正しくインストールされていない事も考えられるので、インストールの確認 も再確認する。
26, Environment
環境変数に問題が有る。
27, Configuration
設定ファイルに問題が有る。
28, Argument
引数に問題が有る。
255
その他のエラー。

変更履歴

Version 2.34  (10th of February, 2024)
  • エラー発生時のUsage表示を止めた。
Version 2.33  (3rd of February, 2024)
  • info.[ch] から汎用コードを集めて tpbar.[ch] を追加した。
Version 2.32  (2nd of April, 2023)
  • Makefile の distclean ルールを修正。
Version 2.31  (1st of April, 2023)
  • configure オプション に --enable-warnall と --with-conffile, --with-backup, --with-expire, --with-sshport を追加。
Version 2.30  (18th of March, 2023)
  • 同期先ホストで psync を起動する ssh のコマンドライン引数を修正した。
Version 2.29  (11th of March, 2023)
  • configure オプションの整理と、細かいバグ修正。
Version 2.28  (3rd of March, 2023)
  • configure のオプションに --enable-sshopts を追加。
Version 2.27  (23rd of February, 2023)
  • バグ修正。
Version 2.26  (23rd of February, 2023)
  • 不要な poll() 呼び出しを廃止した。
Version 2.25  (18th of February, 2023)
  • configure のオプションに --enable-sshpath を追加。
Version 2.24  (5th of February, 2023)
  • 冗長なコードを修正。
Version 2.23  (4th of February, 2023)
  • プログレスバー表示を修正。
Version 2.22  (3rd of February, 2023)
  • configure にプログレスバーのサポートを省くオプションを追加。
Version 2.21  (28th of January, 2023)
  • Makefile の構成ファイル抜けを修正。
Version 2.20  (21st of January, 2023)
  • 進捗表示を書き直した。
    • ローカルとリモートの個別表示を合計表示に変更。
    • ファイル検索の進捗表示を追加。
    • ファイル削除とファイルコピーの進捗表示を追加。
Version 2.19  (5th of August, 2022)
  • 同期ディレクトリ情報に任意のパラメータを追加出来るようにした。 今後の機能追加の前準備。
Version 2.18  (29th of April, 2022)
  • 通信タイムアウトで失敗する事があったので、タイムアウトを無限大に変更した。
Version 2.17  (19th of March, 2022)
  • 動作に影響が無い細かい修正。
    • 進捗表示処理を psync.c から progress.[ch] へ分離。
    • ログ出力の関数名を make_log() から logging() へ変更。
    • シリアライザ/デシリアライザの戻り値を修正。
Version 2.16  (5th of February, 2022)
  • より移植性を上げる修正。
Version 2.15  (22nd of January, 2022)
  • 移植性を上げる修正。
Version 2.14  (8th of August, 2021)
  • 内部関数 progress_init() を修正。
Version 2.13  (31st of July, 2021)
  • 内部関数 progress_update() を修正。
Version 2.12  (18th of July, 2021)
  • README.txt のスペルミスを修正。
Version 2.11  (17th of July, 2021)
  • configure を再生成した。
Version 2.10  (12th of July, 2021)
  • マニュアルに対する "make uninstall" が機能していなかったのを修正。
Version 2.9  (10th of July, 2021)
  • ビルドテスト結果をOS毎に表示するようにした。
Version 2.8  (5th of July, 2021)
  • config.h 無しのビルドに対応。
Version 2.7  (1st of July, 2021)
  • psync_free() をフレッドセーフ化した。
Version 2.6  (28th of June, 2021)
  • manマニュアルのバグを修正。
Version 2.5  (27th of June, 2021)
  • アップロードとダウンロードの進捗を示すプログレスバー表示を追加。
Version 2.4  (13th of June, 2021)
  • 回線速度が遅い場合にアップロード/ダウンロードの進捗表示が途中で止まる現象がまれに発生していたのを修正。
Version 2.3  (30th of May, 2021)
  • 同期ディレクトリに非対応なファイルが含まれているエラーの時、そのファイル名を表示するようにした。
Version 2.2  (13th of March, 2020)
  • 同期相手の SSH ポート番号を指定出来るようにした。
Version 2.1  (4th of March, 2020)
  • 一方向同期モードで一部のファイルが削除されないバグを修正。
  • 識別名は英字か数字で始める仕様に変更した。
Version 2.0  (28th of February, 2020)
  • 一方向同期モードを追加。
  • 設定ファイルでバックアップ保持期限を設定出来るようにした。
Version 1.16  (2nd of August, 2019)
  • Ubuntu でビルドに失敗する問題を修正。 ビルド/インストール環境の修正だけなので、バージョン番号は変更無し。
  • ソースコードを整理。 (3rd of July, 2019)
Version 1.15  (14th of June, 2019)
  • 同期ログを .psync/*/log にテキストファイルで残すようにした。
Version 1.14  (1st of June, 2019)
  • 進捗情報表示のバグを修正。
Version 1.13  (14th of April, 2019)
  • 進捗情報表示の更新周期を1秒にした。
Version 1.12  (31th of March, 2019)
  • 内部的に片方向同期機能を追加。
Version 1.11  (15th of February, 2019)
  • psync_clean() を削除して psync_run() に統合した。
  • タイムアウト時間を30秒から100秒に延長。 遅い3G回線でタイムアウトが発生する事があったので調整した。
Version 1.10  (15th of December, 2018)
  • バックアップファイル削除処理中に中断処理を追加。
Version 1.9  (9th of December, 2018)
  • ファイル同期で削除/更新されたファイルを、最短でも3日間バックアップを保持するようにした。
Version 1.8  (25th of November, 2018)
  • ファイルの削除/更新前にバックアップを作るようにした。 問題なく削除/更新が完了した時点でバックアップは削除され、そうでない場合は 同期ディレクトリ/.psync/lock/[1-9]* にバックアップが残る。
Version 1.7  (22nd of October, 2018)
  • 同期情報保存ファイルの生成タイミングを変更。
Version 1.6  (7th of October, 2018)
  • README.txt と man ドキュメントを追加。
  • ファイルのパーミッションチェック方法を stst() から access() へ変更。
  • アップロード/ダウンロード進捗表示のバグを修正。
Version 1.5  (6th of September, 2018)
  • Make ルールに distclean を追加。
  • 情報の削除日時生成アルゴリズムを変更。
  • 同期ファイル情報収集中の中断判定頻度を上げた。
  • SIGHUP シグナルにも中断処理を入れた。
Version 1.4  (25th of August, 2018)
  • シグナルによる中断処理を安全なコードに修正。
  • エラーメッセージをエラーコードから文字列に変更。
  • psync.c 内の外部公開関数名を psync_*() に変更。
Version 1.3  (16th of August, 2018)
  • エラーメッセージ表示の時、識別名の先頭が数字だった場合に正しい表示をしない問題を修正。
  • その他、動作に影響の無い細かい修正。
Version 1.2  (4th of August, 2018)
  • ソースコードの実装ミスを修正(更新前の状態がディレクトリだった場合の同期処理)。
  • 同期ディレクトリ内に未対応なファイルが含まれていた場合の扱いを「存在しない物として扱う。」から「エラー終了。」に修正。
Version 1.1  (28th of July, 2018)
  • パス名バッファと送受信バッファのサイズを調整。
Version 1.0  (16th of July, 2018)
最初の公開版。
  • MSync の双方向ファイル同期アルゴリズムをベースに新規作成。

ライセンス

本ツールの正式名称は頭1文字目が小文字で2文字目が大文字、それ以降が小文字表記の pSync で、オリジナル配布元は http://kobayasy.com/psync/

この文章を含め pSync の配布ファイルは下記ライセンスの元、使用と再配布を許可する。

Copyright (C) 2018-2023 by Yuichi Kobayashi <kobayasy@kobayasy.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

その他

その他、作者のメモとか、どうでも良い事とか、実は大事な事とか... いろいろ思い付いたらここに追記。

これ以降はいい加減にしかメンテナンスされていおらず、旧バージョンの情報も残っており最新バージョンとは合わない部分もあるので注意。

技術資料

通信プロトコル

ファイル同期の通信プロトコルはこんな感じ。

データフロー

関数とデータフローの関係はこんな感じ。

同期アルゴリズム

双方向ファイル同期アルゴリズムは、psync.c と psync_utils.h で実装されており、psync.h がそのヘッダファイル。

psync_new()

#include "psync.h"
PSYNC *psync_new(const char *dirname, time_t expire, volatile sig_atomic_t *stop)
機能:
同期ディレクトリ前準備。 同じディレクトリに対して重複して前準備は出来ない。
引数:
name
同期ディレクトリを指定。 カレントディレクトリからの相対パスで指定。
expire
削除情報保持期間を秒単位で指定。 例えば30日後まで保持したいならば 2,592,000=30×24×60×60 を指定する。
stop
中断フラグポインタ。
stop=NULL
中断機能を使わない。
*stop=0→1
0から1への変更のみが許された操作で、1を設定すると処理を中断出来る。 中断機能を使う場合は前もって *stop=0 に設定した状態で本関数を呼ぶ事。
戻り値:
同期ディスクリプタを返す。
≠NULL
同期準備完了。
=NULL
同期準備失敗。

psync_free()

#include "psync.h"
void psync_free(PSYNC *psync)
機能:
同期ディレクトリの後処理。
引数:
psync
後処理後、開放する同期ディスクリプタを指定。
戻り値:
(なし)

run()

#include "psync.h"
int run(bool master, PSYNC *psync)
機能:
ファイル同期実行。
引数:
master
動作モードを指定。 同期元に true を、同期相手に false を指定する。
psync->fdin
同期通信受信ディスクリプタを指定。
psync->fdout
同期通信送信ディスクリプタを指定。
psync->info
情報出力ディスクリプタを指定。
戻り値:
正数(0を含む)
ファイル同期成功。
負数
ファイル同期失敗。

使用例

下記はカレントディレクトリからの相対パスディレクトリ Test1/Test2/ を同期するコーディング例。

/* dirsync.c
 * Example code: Synchronize local directory "./Test1/" and "./Test2/"
 */

#include <limits.h>
#include <stdio.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
#include "psync.h"

#define EXPIRE_DEFAULT 400  /* [days] */

typedef struct {
    int status;
    PSYNC *psync;
    bool master;
    pthread_t tid;
} RUN_PARAM;
static void *run_thread(void *data) {
    RUN_PARAM *param = data;

    param->status = run(param->master, param->psync);
    return NULL;
}
static void dirsync(const char *dirname1, const char *dirname2, time_t expire) {
    int fd[2][2] = {
        {-1, -1},
        {-1, -1}
    };
    RUN_PARAM param[2] = {
        {.status = INT_MIN, .psync = NULL},
        {.status = INT_MIN, .psync = NULL}
    };
    unsigned int n1, n2;

    for (n1 = 0; n1 < 2; ++n1) {
        pipe(fd[n1]);
        for (n2 = 0; n2 < 2; ++n2)
            if (fd[n1][n2] == -1)
                goto error;
    }
    param[0].psync = psync_new(dirname1, expire * (60*60*24), NULL);
    if (param[0].psync == NULL)
        goto error;
    param[1].psync = psync_new(dirname2, expire * (60*60*24), NULL);
    if (param[1].psync == NULL)
        goto error;
    param[0].psync->fdin = fd[0][0], param[0].psync->fdout = fd[1][1];
    param[1].psync->fdin = fd[1][0], param[1].psync->fdout = fd[0][1];
    param[0].master = true;
    param[1].master = false;
    if (pthread_create(&param[0].tid, NULL, run_thread, &param[0]) != 0)
      goto error;
    if (pthread_create(&param[1].tid, NULL, run_thread, &param[1]) != 0)
      goto error;
    if (pthread_join(param[0].tid, NULL) != 0)
      goto error;
    if (pthread_join(param[1].tid, NULL) != 0)
      goto error;
error:
    for (n1 = 0; n1 < 2; ++n1)
        if (param[n1].psync != NULL)
            psync_free(param[n1].psync);
    for (n1 = 0; n1 < 2; ++n1)
        for (n2 = 0; n2 < 2; ++n2)
            if (fd[n1][n2] != -1)
                close(fd[n1][n2]);
    printf("status = %d, %d\n", param[0].status, param[1].status);
}

int main(int argc, char *argv[]) {
    dirsync("Test1", "Test2", EXPIRE_DEFAULT);
    return 0;
}

これをビルドするための Makefile はこんな感じ。

# Makefile

CFLAGS = -O2

dirsync : dirsync.o psync.o
	$(CC) -lpthread -o $@ $^

psync.o : psync.c psync_utils.h
dirsync.o : dirsync.c psync.h

%.o : %.c
	$(CC) $(CFLAGS) -c $<

clean :
	$(RM) dirsync
	$(RM) dirsync.o psync.o

シリアライザ

C言語用の手軽に使えるシリアライザが探しても見つからくてなくて自作した。 psync_utils.h で定義しているマクロの WRITE() と READ() がそれ。 扱えるのは整数の数値だけだけど 248bit の値まで対応しているので、全ての整数値型変数に対応できるはず。

READ() の data 型は WRITE() のそれと一致している必要は無いが、値が収まる型である事。 例えば WRITE() 側の型が intmax_t であっても、その値が 255 ならば READ() 側は uin8_t で受ける事が出来る。

WRITE()

WRITE(data, fd, status)
機能:
変数 data の値をシリアライズして、ファイルディスクリプタ fd に書き出す。
引数:
data
シリアライズする数値が代入された任意の整数型変数を指定。 この変数の値は破壊される。 248bit 以下の整数型変数ならば符号付き/符号なし問わず何でも良い。 ポインタではなく整数型変数その物である事。 数値や数式、関数は指定できない。
fd
シリアライズしたデータを書き込むファイルディスクリプタを措定。
status
シリアイズ処理の結果を収納する変数を指定。
正数(0を含む)
シリアイズ成功。
負数
シリアイズ失敗。 原因としては以下が考えられる。 data の型が 248bit を越えている。 fd への書き込みに失敗。
戻り値:
(なし)

READ()

READ(data, fd, status)
機能:
ファイルディスクリプタ fd から読み出したシリアライズされた数値を、デシリアライズして変数 data に代入する。
引数:
data
デシリアイズした数値を代入する任意の整数型変数を指定。 この変数の値は破壊される。 248bit 以下の整数型変数ならば符号付き/符号なし問わず何でも良い。 ポインタではなく整数型変数その物である事。 数値や数式、関数は指定できない。
fd
デシリアライズするデータを読み出すファイルディスクリプタを措定。
status
デシリアイズ処理の結果を収納する変数を指定。
正数(0を含む)
デシリアイズ成功。 この場合、data の値はデシリアイズした数値が入っている。
負数
デシリアイズ失敗。 この場合、data の値は不定で無効。 原因としては以下が考えられる。 fd からの読み出しに失敗。 fd から読み出したデータがシリアライズされたデータでない。 シリアライズ結果の値が data に入りきらずオーバーフロー(アンダーフロー)した。
戻り値:
(なし)

*1シンボリックリンクが使える環境ならば lutimes も実装されていると思われる。
*2始めて使う場合は試してからにして欲しいので、既存のディレクトリを使うのはお進めしない。
*3ASCIIコードの HT(09h) と SP(20h) をスペースと認識。
*4正確にはASCIIコードの NUL(00h) と HT(09h)、LF(0Ah)、CR(0Dh)、SP(20h)、#(23h) を含める事が出来ない。
*5旧バージョンはメンテナンスされないので最新バージョンを使う事をお勧めする。
*6IOアクセスのタイムアウト時間設定が30秒なので、最低でも30秒は待つて欲しい。
*7同期ディレクトリからの相対パス名でバイト換算。
*8最後のワーニングメッセージはC++ならば解るけど、Cのビルドで表示される意図が不明。 Cでは文字列に数値を追加している訳ではなくポインタを加算している表記なので、"a string does not append" なのは当然の事。
Copyright (C) 2018-2024 Yuichi Kobayashi <kobayasy@kobayasy.com>