はじめに
Linux環境で nautilus-dropbox(またはDropboxデーモン)を使っていると、**「PCをサスペンド(スリープ)から復帰させた後、Dropboxの同期が止まってしまう(反応しなくなる)」**という現象に長年悩まされてきました。
一般的には systemd のサスペンドフック(/lib/systemd/system-sleep/)に再起動スクリプトを仕込む方法が有名ですが、この方法には以下のデメリットがあります。
-
sudo(管理者権限)で動くフックの中から、ユーザーセッションのDBUS/Xの状態を扱う必要があり、権限まわりが不安定になりやすい - タイミングや環境変数の受け渡し次第では、サスペンド復帰処理そのものを不安定にしかねない
そこで、管理者権限が一切不要な「D-Bus購読方式」の自動再起動スクリプトを作成しました。systemd-logindが発するPrepareForSleepシグナルを、D-Busの正規の購読機構で受信し、復帰の瞬間に即座にDropboxを再起動します。dbus-monitorのようなeavesdropping方式ではないため、一般ユーザー権限のまま確実に動作します。dotfiles等で管理・共有するのにも最適です。
仕組み(D-Bus購読方式とは?)
dropbox statusの出力をポーリングして判定する方法も考えられますが、これはおすすめしません。実際に検証したところ、サスペンド明けの「同期が止まっている」状態でもdropbox statusが「最新の状態」と誤った自己申告をすることがあり、判定材料として信用できませんでした。
代わりに、OS側が発行するサスペンド/レジュームの通知そのものを直接購読します。systemd-logindは、サスペンド開始直前・レジューム完了直後にそれぞれPrepareForSleepというD-Busシグナルを発行します。これをorg.freedesktop.login1.Managerインターフェース経由で正規に購読すれば、Dropbox側の自己申告に一切頼らず、OSレベルで確実に復帰のタイミングを検知できます。
root権限のフックに頼らず、systemd --userサービスとして常駐させるだけで、ユーザー権限のまま完結します。
さらに、pkill → dropbox start を実行するだけでは「コマンドを投げた」ことしか分かりません。実際に確認したところ、再起動処理を投げても稀に失敗することがあったため、再起動前後でDropboxのPIDを比較し、実際にプロセスが生まれ変わったことを確認してからログに記録するという一手間を加えています。
動作原理を自分の目で確認する
このスクリプトがどう動いているのか、実際にPrepareForSleepシグナルを
生で覗いてみると理解が深まります。
dbus-monitor --system "type='signal',sender='org.freedesktop.login1',interface='org.freedesktop.login1.Manager',member='PrepareForSleep'"
これを実行したままサスペンド→復帰を試すと、以下のようにシグナルが
流れているのが確認できます。
signal time=... sender=:1.xx -> destination=(null destination) serial=xx path=/org/freedesktop/login1; interface=org.freedesktop.login1.Manager; member=PrepareForSleep
boolean true
signal time=... sender=:1.xx -> destination=(null destination) serial=xx path=/org/freedesktop/login1; interface=org.freedesktop.login1.Manager; member=PrepareForSleep
boolean false
boolean trueがサスペンド開始の合図、boolean falseが復帰の合図です。スクリプトはこのfalseを検知した瞬間にDropboxを再起動しています。
仕組みが正しく動いているか不安なときは、まずこのコマンドでシグナルが届いているかどうかを確認するとよいでしょう。
1. 再起動スクリプトの作成
以下のスクリプトを ~/bin/dropbox-watch.pl(または任意のパス)として保存し、実行権限(chmod +x)を与えてください。
PerlのNet::DBusモジュールが必要です。
sudo apt install libnet-dbus-perl
#!/usr/bin/env perl
#
# dropbox-watch.pl
#
# systemd-logindの PrepareForSleepシグナルを D-Busの正規購読で監視。
# サスペンドからの復帰を検知したら Dropboxを再起動する。
#
use strict;
use warnings;
use Net::DBus;
use Net::DBus::Reactor;
use POSIX qw(strftime);
my $LOGFILE = "$ENV{HOME}/.cache/dropbox-watch.log";
# ------------------------------------------------------------
# メイン
# ------------------------------------------------------------
# system busに接続し systemd-logindの Managerオブジェクトを取得する。
my $bus = Net::DBus->system;
my $service = $bus->get_service("org.freedesktop.login1");
my $manager = $service->get_object(
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
);
# サスペンド復帰の通知を監視する。
# PrepareForSleep が true ならサスペンド開始、false なら復帰
$manager->connect_to_signal("PrepareForSleep", sub {
my ($sleeping) = @_;
restart_dropbox() unless $sleeping;
});
Net::DBus::Reactor->main->run;
# ------------------------------------------------------------
# Dropbox 再起動処理
# ------------------------------------------------------------
sub restart_dropbox {
my $old_pid = `pgrep -x dropbox`;
chomp $old_pid;
sleep 10;
system("pkill", "-x", "dropbox");
sleep 2;
system("dropbox", "start");
sleep 2;
my $new_pid = `pgrep -x dropbox`;
chomp $new_pid;
# 再起動前後の PIDを比較して再起動成否を判定する。
# 失敗の場合はログに書き出したあと即終了し systemdの Restart=alwaysに委ねる。
if ($new_pid eq '' || $new_pid eq $old_pid) {
write_log("dropbox restart FAILED (pid unchanged: $old_pid)");
exit 1;
}
write_log("dropbox restarted (pid $old_pid -> $new_pid)");
}
# ------------------------------------------------------------
# ログへ書き込む
# ------------------------------------------------------------
sub write_log {
my ($message) = @_;
open(my $log, '>>', $LOGFILE) or die "log write failed: $!";
my $ts = strftime("%Y-%m-%d %H:%M:%S", localtime);
print $log "$ts $message\n";
close $log;
}
2. systemd --userサービスへの登録
~/.config/systemd/user/dropbox-watch.service として以下を保存してください。
[Unit]
Description=Restart Dropbox after resume from suspend (D-Bus PrepareForSleep watcher)
After=graphical-session.target
[Service]
ExecStart=/usr/bin/perl /home/username/bin/dropbox-watch.pl
Restart=always
RestartSec=5
[Install]
WantedBy=default.target
※ ExecStartのパスはご自身の環境に合わせて書き換えてください。
有効化して常駐させます。sudoは不要です。
systemctl --user daemon-reload
systemctl --user enable --now dropbox-watch.service
状態確認:
systemctl --user status dropbox-watch.service
Active: active (running)と表示されれば起動完了です。
こだわりポイント
-
sleep 10/sleep 2/sleep 2:復帰直後はネットワークやDBUSセッションが安定するまで、pkillの前に猶予を置くようにしました。私の場合はWi-Fi復帰まで実測で約4秒だったため余裕を持たせつつ待ち時間を決めています。お使いの環境に合わせて調整してください。 -
system("pkill", "-x", "dropbox")/system("dropbox", "start")(リスト形式):文字列をシェルに渡さず直接execする形で、余計なシェル解釈を経由しない安全な呼び出しにしています。 -
PIDによる再起動確認:
pkillやdropbox startはコマンドを実行するだけで、実際に成功したかどうかは何も保証してくれません。そこで再起動の前後でpgrep -x dropboxのPIDを比較し、実際に別のプロセスとして生まれ変わったことを確認してからログに記録しています。もし変化がなければ再起動失敗とみなし、その旨をログに残したうえで、あえてスクリプト自身を終了させます。 -
Restart=always/RestartSec=5:万一再起動に失敗してスクリプトが終了しても、systemdが5秒後に自動でプロセスごと立ち上げ直してくれます。プロセスの生存監視をこちらで自作する必要がなく、失敗時は「まっさらな状態でやり直す」というシンプルな設計にできています。
実際のログ
導入後、こんな形でログが残るようになりました。
2026-08-12 16:27:33 dropbox restarted (pid -> 126533)
2026-08-12 16:28:38 dropbox restarted (pid 126533 -> 127264)
2026-08-12 16:29:57 dropbox restarted (pid 127264 -> 127987)
PIDが毎回変わっていることが確認でき、「本当に再起動が成功した」ことの裏付けになります。1行目のようにold_pid側が空になることも稀にありますが(再起動前の時点でDropboxプロセス自体が見当たらなかったケース)、new_pidさえ確認できていれば再起動としては成功しているので、その旨の記録として残ります。
もし再起動に失敗した場合は、こんな形で記録されます。
2026-08-12 xx:xx:xx dropbox restart FAILED (pid unchanged: 127987)
以前のバージョンでは「コマンドを投げた」ことしかログに残らず、実際に成功したのかどうかは分かりませんでした。FAILEDの行が残るようになったことで、後から不調の有無をログだけで確実に追えるようになっています。
おわりに
私の場合は、サスペンドから復帰するとほぼ100%の確率で dropboxの同期が固まっていましたが、このサービスを導入して以来、ノートPCをサスペンド→復帰させた直後でも、数秒待てば確実にDropboxがバックグラウンドで再起動し、同期が正常に行われるようになりました。
root権限のサスペンドフックに不安がある方、sudoなしでユーザー権限だけで完結するDropbox対策を探している方は、ぜひ試してみてください!